Downloads containing DM-Rift.j2as

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

File preview

#pragma require "Heaven.j2t"
#pragma require "DM-Rift-Extra.j2l"

void onLevelLoad() {
	loadExtraLayers();
	loadRiftParts();

	for (int eventID = OBJECT::BLASTERBULLET; eventID <= OBJECT::BULLET; ++eventID) {
		jjObjectPresets[eventID].behavior = BulletWrapper(jjObjectPresets[eventID].behavior);
	}

	Rift(jjObjectPresets[OBJECT::APPLE]);
}

class BulletWrapper : jjBEHAVIORINTERFACE {
	private jjBEHAVIOR nativeBehavior;
	BulletWrapper(const jjBEHAVIOR &in nb) {
		nativeBehavior = nb;
	}

	void onBehave(jjOBJ@ obj) {
		obj.behave(nativeBehavior);

		float xPixelLimit = 1;
		if (obj.xPos > (jjLayers[4].width) * 32 - (xPixelLimit + 1) && obj.xSpeed > 0) {
			obj.xPos = xPixelLimit;
		} else if (obj.xPos < xPixelLimit && obj.xSpeed < 0) {
			obj.xPos = jjLayers[4].width * 32 + (xPixelLimit + 1);
		}
	}
	bool onIsRFBullet(jjOBJ@ obj) {
		return nativeBehavior == BEHAVIOR::RFBULLET;
	}
}

void loadExtraLayers() {
	const int oldTileCount = jjTileCount;
	if (!jjTilesFromTileset("Heaven.j2t", 520, 100)) { //first tileID
		jjAlert("|ERROR: Heaven.j2t not found!", false, STRING::MEDIUM);
		return;
	}

	array<jjLAYER@> heavenLayers = jjLayersFromLevel(
		"DM-Rift-Extra.j2l",
		array<uint> = {6,7}, //Which (1-indexed) layers to copy
		oldTileCount - 520
	);
	if (heavenLayers.length == 0) {
		jjAlert("|ERROR: Heaven.j2l not found!", false, STRING::MEDIUM);
		return;
	}

	// This loop edited in by SE to replace spriteMode usage for a major efficiency boost.
	for (int tileID = 0; tileID < 100; tileID++) {
		jjTileType[oldTileCount + tileID] = 1;
	}

	for (uint layerID = 0; layerID < heavenLayers.length; ++layerID) {
		heavenLayers[layerID].yOffset = 10 * 32;
		heavenLayers[layerID].limitVisibleRegion = false;
		//heavenLayers[layerID].spriteMode = SPRITE::TRANSLUCENTTILE;
	}

	jjLAYER@ blackLayer = jjLAYER(4, jjLayers[6].height);
	blackLayer.generateSettableTileArea();
	blackLayer.xSpeed = jjLayers[6].xSpeed;
	blackLayer.ySpeed = jjLayers[6].ySpeed;
	blackLayer.tileWidth = true;
	for (int y = 70; y < blackLayer.height; y++) {
		for (int x = 0; x < blackLayer.width; x++) {
			blackLayer.tileSet(x, y, 404); //black tile
		}
	}

	array<jjLAYER@> extraBuildingLayers;
	addBuilderLayers( 0, 4, 8, extraBuildingLayers);
	addBuilderLayers(16, 4, 12, extraBuildingLayers);
	addBuilderLayers(36, 4, 10, extraBuildingLayers);
	addBuilderLayers(48, 4, 8, extraBuildingLayers);
	addBuilderLayers(64, 4, 12, extraBuildingLayers);
	addBuilderLayers(86, 4, 10, extraBuildingLayers);
	addBuilderLayers(102, 4, 8, extraBuildingLayers);
	//recreate first two to imitate tiled width
	addBuilderLayers(120, 4, 8, extraBuildingLayers);
	addBuilderLayers(136, 4, 12, extraBuildingLayers);
	//recreate last to imitate tiled width
	addBuilderLayers(-18, 4, 8, extraBuildingLayers);

	jjTexturedBGTexture = TEXTURE::WISETYNESS;
	jjSetFadeColors(70, 64, 66); //above, but a bit darker
	jjUseLayer8Speeds = true;
	jjLayers[7].spriteMode = SPRITE::TRANSLUCENTTILE; //barely visible moon

	array<jjLAYER@> layers;
	layers.insertLast(jjLayers[1]);
	layers.insertLast(jjLayers[2]);
	layers.insertLast(jjLayers[3]);
	layers.insertLast(jjLayers[4]);
	layers.insertLast(jjLayers[5]);
	layers.insertLast(jjLayers[6]);
	layers.insertLast(blackLayer);

	layers.insertAt(layers.length(), extraBuildingLayers);

	layers.insertLast(heavenLayers[0]);
	layers.insertLast(heavenLayers[1]);
	layers.insertLast(jjLayers[7]);
	layers.insertLast(jjLayers[8]);
	jjLayerOrderSet(layers);
}

void addBuilderLayers(int xTile, int yStart, int buildingWidth, array<jjLAYER@>@ layers) {
	int layerWidth = (buildingWidth + 3) & ~0x03;

	int xStart = 0;

	jjLAYER@ baseLayer = jjLAYER(layerWidth, 100);
	baseLayer.generateSettableTileArea();
	baseLayer.xSpeed = 0.75f;
	baseLayer.ySpeed = 0.75f;
	baseLayer.xOffset = 32 * (-1 - (xTile - buildingWidth / 2));
	addBuilding(baseLayer, xStart, yStart, buildingWidth);

	layers.insertLast(baseLayer);

	int i = 10;
	jjLAYER@ layer = jjLAYER(baseLayer);
	layer.spriteMode = SPRITE::SINGLECOLOR;
	layer.spriteParam = 200;
	float speedOffset = (i + 1) / 256.0;
	float offset = (i + 1) * ((5.375 * xTile) - (4 * buildingWidth) + 16) / 32;
	layer.xSpeed -= speedOffset;
	layer.xOffset += offset;
	layers.insertLast(layer);
}

void addBuilding(jjLAYER@ layer, int xStart, int yStart, int width) {
	uint16 topLeft   = 640;
	uint16 topMiddle = 641;
	uint16 topRight  = 642;
	uint16 left   = 650;
	uint16 middle = 671; //light on
	uint16 right  = 652;

	int xEnd = xStart + width;
	int yEnd = layer.height;

	for (int x = xStart; x < xEnd; x++) {
		for (int y = yStart; y < yEnd; y++) {
			uint16 tileID;
			if (y == yStart) {
				if (x == xStart) {
					tileID = topLeft;
				} else if (x == xEnd - 1) {
					tileID = topRight;
				} else {
					tileID = topMiddle;
				}
			} else if (x == xStart) {
				tileID = left;
			} else if (x == xEnd - 1) {
				tileID = right;
			} else {
				tileID = middle;
			}
			layer.tileSet(x, y, tileID);
		}
	}
}

int min(int a, int b) {
	return a < b ? a : b;
}

void onPlayer(jjPLAYER@ player) {
	float xPixelLimit = 1;
	if (player.xPos > (jjLayers[4].width) * 32 - (xPixelLimit + 1) && player.xSpeed > 0) {
		player.offsetPosition(int(-(player.xPos - xPixelLimit)), 0);
	} else if (player.xPos < xPixelLimit && player.xSpeed < 0) {
		player.offsetPosition(int(-(player.xPos - (jjLayers[4].width) * 32 - (xPixelLimit + 1))), 0);
	}
}

namespace math {
	int mod(int a, int b) {
		int r = a % b;
		return r < 0 ? r + b : r;
	}
	int min(int a, int b) {
		return a < b ? a : b;
	}
	int max(int a, int b) {
		return a > b ? a : b;
	}
}

array<LineRiftPart@> parts;

void loadRiftParts() {
	uint customAnimID = 0;
	uint animCount = 4;

	uint frameCount = 64; //must be a power of 2
	array<uint> frameCounts(animCount, frameCount);
	jjANIMSET@ animset = jjAnimSets[ANIM::CUSTOM[customAnimID++]].allocate(frameCounts);

	uint curAnim = animset.firstAnim;

	//speed, type, amplitude, height
	//{xOffset, segmentHeightShift, segmentMask}

	parts.insertLast(LineRiftPart(curAnim++, 1, 0, 4, 4 * 32,
		array<array<int>> = {
			{14, 4, 0x1FF},
			{15, 4, 0xC3},
			{16, 4, 0x1FF}
		}
	));

	parts.insertLast(LineRiftPart(curAnim++, 2, -1, 31, 4 * 32,
		array<array<int>> = {
			{0, 4, 0x3}
		}
	));

	parts.insertLast(LineRiftPart(curAnim++, 1, 1, 7, 8 * 32,
		array<array<int>> = {
			{2, 3, 0x1}
		}
	));

	parts.insertLast(LineRiftPart(curAnim++, 0, 0, 10, 8 * 32,
		array<array<int>> = {
			{5, 3, 0x1}
		}
	));
}

class Rift : jjBEHAVIORINTERFACE {

	Rift(jjOBJ@ objectPreset) {
		objectPreset.behavior = this;
		objectPreset.scriptedCollisions = true;
		objectPreset.playerHandling = HANDLING::PARTICLE;
		objectPreset.bulletHandling = HANDLING::IGNOREBULLET;
		objectPreset.counterEnd = 100;
		objectPreset.isTarget = false;
		objectPreset.isFreezable = false;
		objectPreset.triggersTNT = false;
		objectPreset.deactivates = false;
		objectPreset.causesRicochet = false;
		objectPreset.energy = 0;
		objectPreset.points = 0;
		objectPreset.direction = 1;
	}
	void onBehave(jjOBJ@ obj) {
		switch (obj.state) {
			case STATE::START:
				{
					int xPos = int(obj.xPos);
					int yStart = int(obj.yPos);
					int yEnd = yStart;
					while (!jjMaskedPixel(xPos, yStart - 1)) {
						yStart--;
					}
					while (!jjMaskedPixel(xPos, yEnd)) {
						yEnd++;
					}

					if (yEnd == yStart) {
						yEnd = yStart + 32; //better than nothing
					}

					//adjust one tile up and down:
					yStart -= 32;
					yEnd += 32;

					obj.var[0] = yStart;
					obj.var[1] = yEnd;
				}

				obj.state = STATE::SLEEP;
				break;
		}
	}
	void onDraw(jjOBJ@ obj) {
		int yStart = obj.var[0];
		int yEnd = obj.var[1];
		for (uint i = 0; i < parts.length; i++) {
			parts[i].draw(yStart, yEnd);
		}
	}
}

class LineRiftPart {
	uint curAnim;
	uint frameCount;
	int speed;
	array<int> xStarts;
	int height;

	LineRiftPart(uint curAnim, int speed, int type, int amplitude, int height, array<array<int>> values) {
		this.curAnim = curAnim;
		this.frameCount = jjAnimations[curAnim].frameCount;
		this.speed = speed;
		this.height = height;
		init(type, amplitude, values);
	}

	void init(int type, int amplitude, array<array<int>> values) {
		int xCenter = 0; //could be customized if needed
		int height = this.height;

		int colorCount = 16;

		uint anim = jjAnimations[curAnim].firstFrame;

		int xOffsetMax = 0;
		for (uint valuesIndex = 0; valuesIndex < values.length(); valuesIndex++) {
			array<int> value = values[valuesIndex];
			int xOffset = value[0];
			if (xOffset > xOffsetMax) {
				xOffsetMax = xOffset;
			}
		}

		float period = 1024.0f / height;
		//int amplitude = height / 16;
		int width = (amplitude + xOffsetMax) * 2 + 1;

		int xCenterInImage = width / 2;
		int xStart = xCenter - xCenterInImage;
		this.xStarts.insertLast(xStart);
		this.xStarts.insertLast(math::mod(xStart - 1, jjLayerWidth[4] * 32) + 1);

		int yEndInImage = height;
		int yStartInImage = 0;

		for (uint frameID = 0; frameID < frameCount; frameID++) {
			jjPIXELMAP image(width, height);

			int yFrameStart = frameID * height / frameCount;

			for (uint valuesIndex = 0; valuesIndex < values.length(); valuesIndex++) {
				array<int> value = values[valuesIndex];
				int xOffset = value[0];
				int segmentHeightShift = value[1];
				int segmentHeight = 1 << segmentHeightShift;
				uint segmentMask = value[2];

				for (int yOffset = 0; yOffset < height; yOffset++) {
					int xBase = xCenterInImage + int(jjSin(uint(yOffset * period)) * amplitude);
					int x1 = xBase - xOffset;
					int x2 = xBase + xOffset;
					int y1 = yStartInImage + yOffset;
					int y2 = yEndInImage - yOffset - 1;

					int baseIndex = yFrameStart + yOffset;
					int segmentIndex = baseIndex & (height - 1);
					int colorIndex = (baseIndex >> segmentHeightShift) & ((height >> segmentHeightShift) - 1);

					if (colorIndex <= colorCount && (segmentMask >> (segmentIndex & (segmentHeight - 1))) & 1 != 0) {
						uint8 color;
						if (colorIndex == 0) {
							color = 15; //white
						} else {
							uint8 baseColor = 96; //very light yellowish orange
							color = baseColor + (colorIndex - 1); //gets darker
						}

						if (type <= 0) {
							if (x1 < 0 || y1 < 0 || x1 >= width || y1 >= height) {
								jjDebug("Invalid (x1, y1): (" + x1 + ", " + y1 + "), w: " + width + ", h: " + height);
								continue;
							}
							image[x1, y1] = color;
						}

						if (type >= 0) {
							if (x2 < 0 || y2 < 0 || x2 >= width || y2 >= height) {
								jjDebug("Invalid (x2, y2): (" + x2 + ", " + y2 + "), w: " + width + ", h: " + height);
								continue;
							}
							image[x2, y2] = color;
						}
					}
				}
			}

			if (!image.save(jjAnimFrames[anim + frameID])) {
				jjDebug("Could not save image: " + frameID);
				return;
			}
		}
	}

	void draw(int yStart, int yEnd) {
		uint frameID = (jjGameTicks >> this.speed) & (frameCount - 1);
		uint sprite = jjAnimations[curAnim].firstFrame + frameID;

		int height = this.height;
		int yMid = yStart + ((yEnd - yStart) >> 1);

		for (int y = yMid - height; y >= yStart - height; y -= height) {
			for (uint n = 0; n < xStarts.length(); n++) {
				jjDrawSpriteFromCurFrame(xStarts[n], y, sprite);
			}
		}

		for (int y = yMid; y < yEnd; y += height) {
			for (uint n = 0; n < xStarts.length(); n++) {
				jjDrawSpriteFromCurFrame(xStarts[n], y, sprite);
			}
		}
	}
}