Downloads containing ab19ctf09.j2as

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

File preview

#pragma require "SEroller.asc"
#pragma require "SEminimirv.asc"
#pragma require "SEse.j2t"
#include "SEroller.asc"
#include "SEminimirv.asc"
funcdef int LanternFrameGetter(int, int, int);
enum CustomAnimation {
	animLantern,
	animGarland,
	animRoller,
	animMiniMirv
}
class Catenary {
	private double xt, yt, a;
	Catenary(double s, double x1, double y1, double x2, double y2) {
		double h = x2 - x1;
		double v = y1 - y2;
		double g = sqrt(sqrt(s * s - v * v) / h - 1.0);
		double b = 0.204124145232 / g;
		double p = 0.0;
		while (abs(p - b) > 1e-5) {
			p = b;
			double c = b * 2.0;
			double r = 1.0 / c;
			double t = sinh(r);
			double d = c * t - 1.0;
			b -= d * (1.0 - sqrt(d) / g) / (r * cosh(r) - t);
		}
		a = b * h;
		double e = 2.718281828459 ** (1.0 / b);
		double m = e - 1.0;
		double ve = v * e;
		double am = a * m;
		double ame = am * e;
		double shift = a * log((ve + sqrt(am * ame + ve * ve)) / ame);
		xt = x1 - shift;
		yt = y1 + a * cosh(shift / a);
	}
	double getX() const {
		return xt;
	}
	double getY() const {
		return yt;
	}
	double getA() const {
		return a;
	}
	double getLength(double x1, double x2) const {
		return a * (sinh((x2 - xt) / a) - sinh((x1 - xt) / a));
	}
	double getStep(double x, double s) const {
		double z = s / a + sinh((x - xt) / a);
		return xt + log(z + sqrt(z * z + 1)) * a;
	}
	double opCall(double x) const {
		return yt - a * cosh((x - xt) / a);
	}
}
class Lantern {
	private uint8 palshift;
	private int x, y, type;
	private jjANIMATION@ anim;
	Lantern(double xPos, double yPos, uint sprite, int color) {
		const array<uint8> palshifts = {24, 8, 24, 72, 0};
		x = int(xPos - 15.0);
		y = int(yPos + 1.5);
		@anim = jjAnimations[sprite];
		type = color % palshifts.length();
		palshift = palshifts[type];
	}
	void draw(jjCANVAS@ canvas, int order, int row, LanternFrameGetter@ getFrame) const {
		canvas.drawSpriteFromCurFrame(x, y, anim + getFrame(type, order, row), 0, SPRITE::PALSHIFT, palshift);
	}
}
class Garland {
	private Catenary@ arc;
	private double left, right, top, bottom;
	private uint sprite;
	private array<Lantern@> lanterns;
	Garland(int x1, int y1, int x2, int y2, double lengthMultiplier, double lanternSpacing, uint lanternSprite) {
		double xl = x1 << 5 | 16;
		double xr = x2 << 5 | 15;
		double yl = y1 << 5 | 16;
		double yr = y2 << 5 | 16;
		double width = xr - xl;
		double height = yr - yl;
		double length = sqrt(width * width + height * height) * lengthMultiplier;
		@arc = Catenary(length, xl, yl, xr, yr);
		left = xl +  8.0;
		right = xr - 8.0;
		top = yl < yr ? yl : yr;
		double x = arc.getX();
		bottom = x < left ? left : x > right ? right : arc(x);
		int segments = int(length / lanternSpacing);
		double segment = length / segments;
		double lanternX = xl;
		for (int i = 1; i < segments; i++) {
			lanternX = arc.getStep(lanternX, segment);
			int m = i - 1;
			if (segments - i - 1 < m)
				m = segments - i - 1;
			lanterns.insertLast(Lantern(lanternX, arc(lanternX), lanternSprite + getLanternSprite(i, segments, lanternX), m % 9));
		}
	}
	private int getLanternSprite(int id, int count, double x) const {
		if (count & 1 != 0 && x > jjLayers[4].width << 4)
			id = ~id;
		return id & 1;
	}
	void draw(jjCANVAS@ canvas, int order, int row, LanternFrameGetter@ getFrame) const {
		if (sprite != 0) {
			canvas.drawSpriteFromCurFrame(int(left), int(top), sprite);
			for (int i = lanterns.length(); i-- != 0;) {
				lanterns[i].draw(canvas, order, row, getFrame);
			}
		}
	}
	void generateSprite(uint frame, uint8 color) {
		int64 l = int64(left + 0.5);
		int64 r = int64(right + 0.5);
		int64 t = int64(top + 0.5);
		int64 b = int64(bottom + 0.5);
		int width = r - l + 1;
		int height = b - t + 1;
		jjPIXELMAP image(width, height);
		int prev = -1;
		for (int i = 0; i < width; i++) {
			int cur = int64(arc(l + i) + 0.5) - t;
			image[i, cur] = color;
			if (i != 0) {
				int step = cur - prev;
				while (step > 1) {
					step--;
					image[i - 1, cur - step] = color;
				}
				while (step < -1) {
					step++;
					image[i, cur - step] = color;
				}
			}
			prev = cur;
		}
		if (image.save(jjAnimFrames[frame]))
			sprite = frame;
	}
}
class Decorator {
	private array<Garland@> garlands;
	private uint lanternSprite;
	void draw(jjCANVAS@ canvas, int order, int row) const {
		LanternFrameGetter@ getFrame = lanternPatternDigitalRitual;
		string music = lowercase(jjMusicFileName);
		if (music == "yukatan.it")
			@getFrame = lanternPatternYukatan;
		else if (music == "digital ritual.mo3")
			@getFrame = lanternPatternDigitalRitual;
		for (int i = garlands.length(); i-- != 0;) {
			garlands[i].draw(canvas, order, row, getFrame);
		}
	}
	void createLanternSprites() {
		const array<int> tiles = {566, 570};
		const int frameCount = 6;
		lanternSprite = jjAnimSets[ANIM::CUSTOM[animLantern]].allocate(array<uint>(2, frameCount));
		for (int i = 0; i < 2; i++) {
			jjPIXELMAP src(tiles[i]), dest;
			int dark = 255, bright = 0;
			for (int j = 0; j < 32; j++) {
				for (int k = 0; k < 32; k++) {
					uint8 pixel = src[k, j];
					if (pixel != 0) {
						int light = jjPalette.color[pixel].getLight();
						if (light > bright)
							bright = light;
						if (light < dark)
							dark = light;
					}
				}
			}
			int range = bright - dark + 1;
			uint anim = jjAnimations[lanternSprite + i];
			for (int l = 0; l < frameCount; l++) {
				for (int j = 0; j < 32; j++) {
					for (int k = 0; k < 32; k++) {
						uint8 pixel = src[k, j];
						if (pixel != 0)
							dest[k, j] = 7 - (jjPalette.color[pixel].getLight() - dark) * (l + (9 - frameCount)) / range | 16;
					}
				}
				dest.save(jjAnimFrames[anim + l]);
			}
		}
	}
	void hangGarlands() {
		array<int> x(64, -1), y(64, -1);
		for (int i = 0; i < jjLayers[4].width; i++) {
			for (int j = 0; j < jjLayers[4].height; j++) {
				if (jjEventGet(i, j) == AREA::PATH) {
					int id = jjParameterGet(i, j, 0, 6);
					if (x[id] != -1 && x[id] != i)
						garlands.insertLast(Garland(x[id], y[id], i, j, 1.05, 50.0, lanternSprite));
					x[id] = i;
					y[id] = j;
					jjEventSet(i, j, 0);
				}
			}
		}
		int count = garlands.length();
		jjANIMSET@ animSet = jjAnimSets[ANIM::CUSTOM[animGarland]];
		animSet.allocate(array<uint> = {count});
		jjANIMATION@ anim = jjAnimations[animSet];
		for (int i = 0; i < count; i++) {
			garlands[i].generateSprite(anim + i, 127);
		}
	}
}
Decorator decorator;
se::DefaultAmmoDisplayHook ammoDisplayHook;
se::DefaultNetworkHook networkHook;
string lowercase(string &in s) {
	for (int i = s.length(); i-- != 0;) {
		if (s[i] > 64 && s[i] < 91)
			s[i] ^= 32;
	}
	return s;
}
int lanternPatternDigitalRitual(int type, int order, int row) {
	switch (type) {
		case 0:
			if (order >= 14 && order < 30 || order >= 32 && order < 36 || order >= 50 && order < 66) {
				if (row < 4)
					return 5 - row;
				if (row >= 4 && row < 9)
					return 9 - row;
				if (row >= 16 && row < 21)
					return 21 - row;
				if (order & 1 != 0) {
					if (order == 25 || order == 35 || order == 61 || order == 65) {
						if (row >= 32 && row < 36)
							return 37 - row;
						if (row >= 36 && row < 41)
							return 41 - row;
						if (row >= 48 && row < 53)
							return 53 - row;
					} else if (order < 29 || order >= 50) {
						if (row >= 48 && row < 52)
							return 53 - row;
						if (row >= 52 && row < 57)
							return 57 - row;
					}
				} else if (order >= 22 && order < 28 || order == 34 || order >= 58) {
					if (row >= 40 && row < 45)
						return 45 - row;
					if (row >= 48 && row < 53)
						return 53 - row;
				}
			} else if (order == 66 && row < 5) {
				return 5 - row;
			}
			break;
		case 1:
			if (order >= 14 && order < 30 || order >= 32 && order < 36 || order >= 50 && order < 66) {
				if (row & ~3 != 20 && row & ~3 != 32 && (row < 52 || order != 25 && order != 29 && order != 35 && order != 61 && order != 65))
					return 5 - (row & 3);
			} else if (order == 30 || order == 31) {
				if (row < 16)
					return 5 - (row & 3);
			} else if (order >= 36 && order < 40) {
				if (row < 5)
					return 5 - row;
				if (row >= 8 && row < 13)
					return 13 - row;
				if (row >= 24 && row < 29)
					return 29 - row;
				if (row >= 28 && row < 33)
					return 33 - row;
				if (row >= 52)
					return 5 - (row & 3);
			} else if (order >= 40 && order < 48) {
				if (row < 5)
					return 5 - row;
				if (row >= 8 && row < 13)
					return 13 - row;
				if (row >= 28 && row < 33)
					return 33 - row;
				if (row >= 32 && row < 37)
					return 37 - row;
				if (row >= 40 && row < 45)
					return 45 - row;
				if (order & 1 != 0 && row >= 56 || order == 47 && row >= 44)
					return 5 - (row & 3);
			} else if (order >= 66) {
				return 0;
			} else if (row < 32) {
				if ((row >> 2) % 3 != 2)
					return 5 - (row & 3);
			} else if (order == 3 || order == 7 || order == 9 || order == 11 || order == 13 || order == 49) {
				if (row >= 48 && row & ~3 != 52)
					return 5 - (row & 3);
			} else if (order == 5) {
				if (row >= 48 && row < 53)
					return 53 - row;
			} else if (order == 10 || order == 12) {
				if (row >= 36 && row < 41)
					return 41 - row;
				if (row >= 44 && row < 48)
					return 49 - row;
				if (row >= 48 && row < 53)
					return 53 - row;
				if (row >= 56 && row < 61)
					return 61 - row;
			} else if (order == 48) {
				if (row & ~3 != 32 && row & ~3 != 56)
					return 5 - (row & 3);
			}
			break;
		case 2:
			if (order >= 14 && order < 30 || order >= 32 && order < 36 || order >= 50 && order < 66) {
				if (row >= 8 && row < 13)
					return 13 - row;
				if (row >= 12 && row < 17)
					return 17 - row;
				if (order & 1 != 0) {
					if (order == 25 || order == 35 || order == 61 || order == 65) {
						if (row >= 24 && row < 28)
							return 29 - row;
						if (row >= 28 && row < 33)
							return 33 - row;
						if (row >= 40 && row < 45)
							return 45 - row;
					} else if (order < 29 || order >= 50) {
						if (row >= 36 && row < 40)
							return 41 - row;
						if (row >= 40 && row < 44)
							return 45 - row;
						if (row >= 44 && row < 49)
							return 49 - row;
						if (row >= 56 && row < 60)
							return 61 - row;
						if (row >= 60 && row < 65)
							return 65 - row;
					}
				} else if (order >= 22 && order < 28 || order == 34 || order >= 58) {
					if (row >= 36 && row < 41)
						return 41 - row;
					if (row >= 44 && row < 49)
						return 49 - row;
					if (row >= 52 && row < 57)
						return 57 - row;
				}
			} else if (order == 66 && row < 5) {
				return 5 - row;
			}
			break;
		case 3:
			if (order >= 2 && order < 14 || order == 48 || order == 49) {
				if (order >= 6) {
					if (row >= 20 && row < 25)
						return 25 - row;
					if (row >= 56 && row < 60)
						return 61 - row;
				}
				if (row >= 44 && row < 48)
					return 49 - row;
				if (row >= 48 && row < 53)
					return 53 - row;
				if (order >= 5 && row >= 60 && row < 65)
					return 65 - row;
			} else if (order >= 18 && order < 36) {
				if (order >= 26) {
					if (row >= 48 && row < 50)
						return 53 - row;
					if (row >= 50 && row < 54)
						return 55 - row;
					if (row >= 54 && row < 59)
						return 59 - row;
					if (row >= 60 && row < 65)
						return 65 - row;
				}
				if (order >= 22 && row >= 20 && row < 25)
					return 25 - row;
				if (row >= 44 && row < 49)
					return 49 - row;
			} else if (order >= 40 && order < 48) {
				if (row >= 16 && row < 21)
					return 21 - row;
				if (row >= 32 && row < 37)
					return 37 - row;
				if (row >= 44 && row < 49)
					return 49 - row;
				if (row >= 60 && row < 65)
					return 65 - row;
			} else if (order >= 54 && order != 57 && order < 66) {
				if (row >= 44 && row < 48)
					return 49 - row;
			}
			break;
		case 4:
			if (order == 1 || order == 4) {
				if (row >= 22 && row < 32)
					return (row - 20) >> 1;
				if (row >= 32 && row < 42)
					return (43 - row) >> 1;
				if (row >= 44 && row < 50)
					return (51 - row) >> 1;
				if (row >= 52 && row < 60)
					return (61 - row) >> 1;
			} else if (order == 5 || order == 13 || order == 49) {
				if (row >= 48 && row < 53)
					return 53 - row;
			} else if (order == 32) {
				if (row < 4)
					return 4 - row;
			} else if (order == 66) {
				if (row >= 14 && row < 22)
					return (25 - row) >> 1;
				if (row >= 22 && row < 32)
					return (33 - row) >> 1;
			}
			break;
	}
	return 0;
}
int lanternPatternYukatan(int type, int order, int row) {
	switch (type) {
		case 0:
			if (order < 26 || order >= 34) {
				if (row >= 4 && row < 9)
					return 9 - row;
				if (row >= 12 && row < 17)
					return 17 - row;
				if (row >= 24 && row < 29)
					return 29 - row;
				if (row >= 32 && row < 37)
					return 37 - row;
				if (row >= 40 && row < 45)
					return 45 - row;
			}
			break;
		case 1:
			if (order < 52) {
				int beat;
				if (order < 4)
					beat = row & 15;
				else if (order == 5 && row >= 52)
					beat = row - 52;
				else if (order == 13 && row >= 36)
					beat = row & 3 + (row == 40 || row == 52 ? 4 : 0);
				else if (order == 33 && row >= 38)
					beat = row >= 46 && row < 54 ? row - 46 : row >= 62 ? row - 62 : row & 1;
				else if (order >= 34 && order < 46)
					beat = row + 4 & 7;
				else
					beat = row & 7;
				return beat < 5 ? 5 - beat : 0;
			}
			break;
		case 2:
			if (order < 26 || order >= 34) {
				if (row >= 20 && row < 25)
					return 25 - row;
				if (row >= 28 && row < 33)
					return 33 - row;
				if (row >= 48 && row < 53)
					return 53 - row;
				if (row >= 56 && row < 61)
					return 61 - row;
			}
			break;
		case 3:
			if (order >= 6 && order < 42) {
				if (row >= 32 && row < 37)
					return 37 - row;
				if (order >= 7 && order < 20 || order == 25) {
					int power = order < 14 ? 4 : 2;
					if (row < power)
						return power - row;
					if (row >= 8 && row < 8 + power)
						return 8 + power - row;
				}
			}
			break;
		case 4:
			if (order & 3 == 1 && row >= 36 && order != 1 && order != 25) {
				int beat = row >= 52 ? row - 52 : row + 4 & 7;
				return beat < 5 ? 5 - beat : 0;
			}
			if (order & 3 == 2 && row >= 4 && row < 20 && (order < 34 || order >= 46)) {
				int beat = row + 4 & 7;
				return beat < 5 ? 5 - beat : 0;
			}
			break;
	}
	return 0;
}
void removeSpritePaletteReferences() {
	array<int> mapping(256);
	for (int i = 1; i < 96; i++) {
		jjPALCOLOR color = jjPalette.color[i];
		int best = 0x40000;
		for (int j = 96; j < 256; j++) {
			jjPALCOLOR match = jjPalette.color[j];
			int red = int(match.red) - color.red;
			int green = int(match.green) - color.green;
			int blue = int(match.blue) - color.blue;
			int dist = red * red + green * green + blue * blue;
			if (dist < best) {
				best = dist;
				mapping[i] = j;
			}
		}
	}
	for (int i = 96; i < 256; i++) {
		mapping[i] = i;
	}
	for (uint i = 1; i < jjTileCount; i++) {
		jjPIXELMAP tile(i);
		for (int j = 0; j < 32; j++) {
			for (int k = 0; k < 32; k++) {
				tile[k, j] = mapping[tile[k, j]];
			}		
		}
		tile.save(i, true);
	}
}
void setLevelPalette() {
	jjPAL@ pal = jjPalette;
	pal.reset();
	for (int i = 96; i < 256; i++) {
		pal.color[i].red = pal.color[i].red * 2 / 3;
		pal.color[i].green = pal.color[i].green * 2 / 3;
		if (pal.color[i].red / 2 > pal.color[i].blue)
			pal.color[i].blue = pal.color[i].red / 2;
		if (pal.color[i].green / 2 > pal.color[i].blue)
			pal.color[i].blue = pal.color[i].green / 2;
	}
	/*pal.color[96] = jjPALCOLOR(191, 213, 237);
	pal.color[120] = jjPALCOLOR(155, 177, 203);
	pal.color[123] = jjPALCOLOR(47, 96, 150);
	pal.color[126] = jjPALCOLOR(37, 75, 121);
	pal.color[138] = jjPALCOLOR(26, 54, 91);
	pal.color[144] = jjPALCOLOR(18, 38, 68);
	pal.color[167] = jjPALCOLOR(15, 33, 61);
	pal.color[200] = jjPALCOLOR(12, 27, 53);
	pal.color[206] = jjPALCOLOR(7, 16, 42);
	pal.color[219] = jjPALCOLOR(5, 11, 38);
	pal.color[242] = jjPALCOLOR(4, 19, 50);*/
	pal.color[96] = jjPALCOLOR(228, 226, 244);
	pal.color[120] = jjPALCOLOR(170, 165, 219);
	pal.color[123] = jjPALCOLOR(132, 126, 204);
	pal.color[126] = jjPALCOLOR(109, 102, 194);
	pal.color[138] = jjPALCOLOR(74, 66, 167);
	pal.color[144] = jjPALCOLOR(88, 80, 185);
	pal.color[167] = jjPALCOLOR(65, 57, 147);
	pal.color[200] = jjPALCOLOR(40, 35, 91);
	pal.color[206] = jjPALCOLOR(54, 47, 121);
	pal.color[219] = jjPALCOLOR(26, 23, 59);
	pal.color[242] = jjPALCOLOR(17, 15, 38);
	pal.apply();
}
void adjustMask() {
	const array<int> emptyMasks = {85, 86, 87, 107, 430, 431, 432, 454, 567, 569};
	jjMASKMAP mask;
	for (int i = emptyMasks.length(); i-- != 0;) {
		mask.save(emptyMasks[i], true);
	}
	jjMASKMAP(21).save(380, true);
	jjMASKMAP(23).save(382, true);
}
void loadBackground() {
	int start = jjTileCount;
	const string originalTileset = jjTilesetFileName;
	if (jjTilesFromTileset("SEse.j2t", 10, 570)) {
		jjLAYER@ layer = jjLayers[8];
		layer.generateSettableTileArea();
		for (int i = 0; i < layer.height; i++) {
			for (int j = 0; j < layer.width; j++) {
				int tileID = start + i * 10 + j % 10 + j / 10 * 190;
				layer.tileSet(j, i, tileID);
				// JJ2+ bug workaround
				jjTileType[tileID] = 0;
			}
		}
	}
	// JJ2+ bug workaround
	jjTilesFromTileset(originalTileset, 0, 0);
}
bool onDrawAmmo(jjPLAYER@ player, jjCANVAS@ canvas) {
	return ammoDisplayHook.draw(player, canvas);
}
void onDrawLayer4(jjPLAYER@, jjCANVAS@ canvas) {
	decorator.draw(canvas, jjGetModOrder(), jjGetModRow());
}
void onLevelLoad() {
	decorator.createLanternSprites();
	removeSpritePaletteReferences();
	setLevelPalette();
	adjustMask();
	loadBackground();
	decorator.hangGarlands();
	jjLayers[2].spriteMode = SPRITE::TRANSLUCENT;
	se::roller.loadAnims(jjAnimSets[ANIM::CUSTOM[animRoller]]);
	se::roller.loadSamples(array<SOUND::Sample> = {SOUND::INTRO_BLOW});
	se::roller.setAsWeapon(3, ammoDisplayHook, networkHook);
	se::miniMirv.loadAnims(jjAnimSets[ANIM::CUSTOM[animMiniMirv]]);
	se::miniMirv.loadSamples(array<SOUND::Sample> = {SOUND::INTRO_BOEM1, SOUND::INTRO_BOEM2});
	se::miniMirv.setAsWeapon(9, ammoDisplayHook, networkHook);
}
void onLevelReload() {
	setLevelPalette();
}
void onReceive(jjSTREAM &in packet, int clientID) {
	networkHook.process(packet, clientID);
}