Downloads containing elevatorEditor.asc

Downloads
Name Author Game Mode Rating
TSF with JJ2+ Only: Elevator Cranky Mutator N/A Download file

File preview

const int ELEVATOR_EDITOR_ACT_PREV = 1;
const int ELEVATOR_EDITOR_ACT_NEXT = 2;
const int ELEVATOR_EDITOR_ACT_ADD = 3;
const int ELEVATOR_EDITOR_ACT_DELETE = 4;
const int ELEVATOR_EDITOR_ACT_SELECT = 5;
const int ELEVATOR_EDITOR_ACT_HELP = 6;
const int ELEVATOR_EDITOR_ACT_BACK = 7;
const int ELEVATOR_EDITOR_ACT_SAVE = 8;
const int ELEVATOR_EDITOR_ACT_HELP_SCROLL_UP = 9;
const int ELEVATOR_EDITOR_ACT_HELP_SCROLL_DOWN = 10;
const int ELEVATOR_EDITOR_ACT_CONTROL_MODE = 11;
const int ELEVATOR_EDITOR_ACT_ELEVATOR_TYPE = 12;
const int ELEVATOR_EDITOR_ACT_SPEED = 13;

const int ELEVATOR_EDIT_NONE = 0;
const int ELEVATOR_EDIT_CONTROLLABLE = 1;
const int ELEVATOR_EDIT_AUTONOMOUS = 2;
const int ELEVATOR_EDIT_COMPONENT = 3;
const int ELEVATOR_EDIT_LIMIT = 4;
const int ELEVATOR_EDIT_BOLL = 5;
const int ELEVATOR_EDIT_ERASE = 6;
const int ELEVATOR_EDIT_BACKGROUND_COMPONENT = 7;

bool ElevatorEditorOpen = false;
bool ElevatorEditorHelp = false;
int ElevatorEditorSelectedId = 1;
int ElevatorEditorSelectedTool = ELEVATOR_EDIT_NONE;
bool ElevatorEditorMouseWasDown = false;
int ElevatorEditorLastClick = -9999;
bool ElevatorEditorDirty = false;
int ElevatorEditorHelpScroll = 0;
int ElevatorEditorControlMode = ELEVATOR_CONTROL_UP_DOWN;
int ElevatorEditorElevatorType = ELEVATOR_TYPE_NORMAL;
int ElevatorEditorSpeed = ELEVATOR_DEFAULT_SPEED;
DbWindow ElevatorEditorWindow;

bool ElevatorEditor_IsLocalAdmin()
{
	return jjIsServer || jjLocalPlayers[0].isAdmin;
}

bool Elevator_CheckNumber(const string &in text)
{
	for(int i = int(text.length()) - 1; i >= 0; i--)
		if(text[i] < 48 || text[i] > 57) return false;
	return text.length() > 0;
}

bool ElevatorAdmin_OnLocalChat(string &in text, CHAT::Type chatType)
{
	array<string> parts = text.split(" ");
	if(parts.length != 3 || !jjRegexMatch(parts[0], "^!elevator$", true)) return false;
	if(!ElevatorEditor_IsLocalAdmin())
	{
		jjAlert("Only admins can use elevator commands.");
		return true;
	}
	if(!Elevator_CheckNumber(parts[2]))
	{
		jjAlert("Elevator id must be a number");
		return true;
	}
	int id = parseInt(parts[2]);
	if(elevatorIds.find(id) < 0)
	{
		jjAlert("Elevator " + id + " does not exist.");
		return true;
	}
	elevatorInfoClass eInfo;
	elevatorInfo.get(id + "", eInfo);
	elevatorCmdClass eCmd;
	elevatorCmd.get(id + "", eCmd);
	if(jjRegexMatch(parts[1], "up", true) || jjRegexMatch(parts[1], "climb", true))
	{
		if(eInfo.locked)
		{
			jjAlert("Elevator is locked, consider unlocking first with |||!elevator lock |<id>");
			jjAlert("Alternatively to force unlock and go up you can use |||!elevator fup |<id>");
		}
		else { eCmd.cmd = 1; elevatorCmd.set(id + "", eCmd); }
		return true;
	}
	if(jjRegexMatch(parts[1], "down", true) || jjRegexMatch(parts[1], "descend", true))
	{
		if(eInfo.locked)
		{
			jjAlert("Elevator is locked, consider unlocking first with |||!elevator lock |<id>");
			jjAlert("Alternatively to force unlock and go down you can use |||!elevator fdown |<id>");
		}
		else { eCmd.cmd = 2; elevatorCmd.set(id + "", eCmd); }
		return true;
	}
	if(jjRegexMatch(parts[1], "lock", true) || jjRegexMatch(parts[1], "stop", true))
	{
		eCmd.cmd = 0;
		eCmd.cmdBack = true;
		elevatorCmd.set(id + "", eCmd);
		setLocked(id, !eInfo.locked);
		return true;
	}
	if(jjRegexMatch(parts[1], "fup", true))
	{
		setLocked(id, false);
		eCmd.cmd = 1;
		elevatorCmd.set(id + "", eCmd);
		return true;
	}
	if(jjRegexMatch(parts[1], "fdown", true))
	{
		setLocked(id, false);
		eCmd.cmd = 2;
		elevatorCmd.set(id + "", eCmd);
		return true;
	}
	if(jjRegexMatch(parts[1], "location", true))
	{
		jjAlert("Location of bottom piece for " + id + " is: " + int(jjObjects[eInfo.botObjId].xPos / 32) + " " + int(jjObjects[eInfo.botObjId].yPos / 32));
		return true;
	}
	return false;
}

bool ElevatorEditor_OnLocalChat(string &in text, CHAT::Type chatType)
{
	if(!jjRegexMatch(text, "^!elevatorEdit$", true) && !jjRegexMatch(text, "^!elevatorEditor$", true)) return false;
	if(!ElevatorEditor_IsLocalAdmin())
	{
		jjAlert("Only admins can open the Elevator Editor.");
		return true;
	}
	ElevatorEditorOpen = true;
	ElevatorEditorHelp = false;
	ElevatorEditorHelpScroll = 0;
	ElevatorEditorSelectedTool = ELEVATOR_EDIT_NONE;
	ElevatorEditorMouseWasDown = false;
	ElevatorEditorWindow.mouseWasDown = false;
	ElevatorEditorWindow.dragging = false;
	Elevator_LoadEditorPlacements();
	if(!Elevator_PlacementIdExists(ElevatorEditorSelectedId)) ElevatorEditorSelectedId = ElevatorEditor_FirstExistingId();
	ElevatorEditor_LoadSelectedOptions();
	return true;
}

void ElevatorEditor_OnMain()
{
	if(ElevatorEditorOpen && !ElevatorEditor_IsLocalAdmin()) ElevatorEditor_Close();
	if(ElevatorEditorOpen) ElevatorEditor_ProcessTileClick();
}

void ElevatorEditor_Close()
{
	if(ElevatorEditorDirty)
	{
		Elevator_SavePlacements();
		ElevatorEditorDirty = false;
	}
	ElevatorEditorOpen = false;
	ElevatorEditorHelp = false;
	ElevatorEditorHelpScroll = 0;
	ElevatorEditorSelectedTool = ELEVATOR_EDIT_NONE;
	ElevatorEditorMouseWasDown = false;
	ElevatorEditorWindow.mouseWasDown = false;
	ElevatorEditorWindow.dragging = false;
	ElevatorEditorWindow.controls.resize(0);
}

void ElevatorEditor_OnPlayerInput(jjPLAYER@ play)
{
	if(!ElevatorEditorOpen || !play.isLocal) return;
	DbResult result;
	if(DbProcessKeyboard(@ElevatorEditorWindow, play, @result)) ElevatorEditor_HandleResult(@result);
}

void ElevatorEditor_Draw(jjPLAYER@ play, jjCANVAS@ canvas)
{
	if(!ElevatorEditorOpen || !play.isLocal || !ElevatorEditor_IsLocalAdmin()) return;
	ElevatorEditorWindow.preferencesFile = "elevatorDialogueBox.asdat";
	DbBegin(@ElevatorEditorWindow, "elevatorEditor", "Elevator Editor", 12, 12, 430, 462);
	ElevatorEditorWindow.closeButton = true;
	ElevatorEditorWindow.draggable = true;
	ElevatorEditorWindow.titleBar = true;
	ElevatorEditorWindow.pad = 14;
	DbDrawFrame(canvas, @ElevatorEditorWindow);
	int x, y, w, h;
	DbContentRect(@ElevatorEditorWindow, x, y, w, h);
	if(ElevatorEditorHelp)
	{
		canvas.drawString(x, y, "Help", STRING::MEDIUM, STRING::NORMAL);
		int textY = y + 28;
		int maxY = ElevatorEditorWindow.y + ElevatorEditorWindow.h - 48;
		ElevatorEditorHelpScroll = DbDrawScrollableSmallText(canvas, @ElevatorEditorWindow, x, textY, w, maxY, ElevatorEditor_HelpText(), ElevatorEditorHelpScroll, true, ELEVATOR_EDITOR_ACT_HELP_SCROLL_UP, ELEVATOR_EDITOR_ACT_HELP_SCROLL_DOWN);
		DbDrawButton(canvas, @ElevatorEditorWindow, x, ElevatorEditorWindow.y + ElevatorEditorWindow.h - 30, w, 16, ELEVATOR_EDITOR_ACT_BACK, 0, 0, "Back");
	}
	else
	{
		DbDrawStepper(canvas, @ElevatorEditorWindow, x, y, 28, ELEVATOR_EDITOR_ACT_NEXT, 0, -1, 1, "" + ElevatorEditorSelectedId);
		DbDrawButton(canvas, @ElevatorEditorWindow, x + 78, y, 60, 16, ELEVATOR_EDITOR_ACT_ADD, 0, 0, "Add");
		DbDrawButton(canvas, @ElevatorEditorWindow, x + 146, y, 70, 16, ELEVATOR_EDITOR_ACT_DELETE, 0, 0, "Delete");
		DbDrawButton(canvas, @ElevatorEditorWindow, x + w - 50, y, 50, 16, ELEVATOR_EDITOR_ACT_HELP, 0, 0, "Help");
		y += 40;
		ElevatorEditor_DrawTool(canvas, x, y, ELEVATOR_EDIT_CONTROLLABLE, 32, "Controllable elevator");
		DbDrawStepper(canvas, @ElevatorEditorWindow, x + 252, y, 116, ELEVATOR_EDITOR_ACT_CONTROL_MODE, 0, -1, 1, ElevatorEditor_ControlModeText(ElevatorEditorControlMode));
		y += 40;
		ElevatorEditor_DrawTool(canvas, x, y, ELEVATOR_EDIT_AUTONOMOUS, 80, "Autonomous elevator");
		y += 40;
		ElevatorEditor_DrawTool(canvas, x, y, ELEVATOR_EDIT_COMPONENT, 64, "Elevator component");
		y += 40;
		ElevatorEditor_DrawTool(canvas, x, y, ELEVATOR_EDIT_BACKGROUND_COMPONENT, 64, "Background component");
		y += 40;
		ElevatorEditor_DrawTool(canvas, x, y, ELEVATOR_EDIT_BOLL, 48, "Boll Platform elevator piece");
		y += 40;
		ElevatorEditor_DrawTool(canvas, x, y, ELEVATOR_EDIT_LIMIT, 24, "Elevator limit");
		y += 40;
		ElevatorEditor_DrawTool(canvas, x, y, ELEVATOR_EDIT_ERASE, 15, "Delete tile");
		y += 38;
		DbDrawStepper(canvas, @ElevatorEditorWindow, x, y, 116, ELEVATOR_EDITOR_ACT_SPEED, 0, -1, 1, "Speed: " + Elevator_SpeedText(ElevatorEditorSpeed));
		y += 28;
		DbDrawButton(canvas, @ElevatorEditorWindow, x, y, 270, 16, ELEVATOR_EDITOR_ACT_ELEVATOR_TYPE, 0, 0, "Elevator Type: " + ElevatorEditor_TypeText(ElevatorEditorElevatorType));
		string saveText = ElevatorEditorDirty ? "Save *" : "Save";
		int saveY = ElevatorEditorWindow.y + ElevatorEditorWindow.h - 48;
		DbDrawButton(canvas, @ElevatorEditorWindow, x, saveY, 80, 16, ELEVATOR_EDITOR_ACT_SAVE, 0, 0, saveText);
		canvas.drawString(x, saveY + 20, "Restart the levels for the changes to", STRING::SMALL, STRING::PALSHIFT, 24);
		canvas.drawString(x, saveY + 32, "take effect", STRING::SMALL, STRING::PALSHIFT, 24);
	}
	ElevatorEditor_DrawFocus(canvas);
	DbResult result;
	if(DbProcessMouse(@ElevatorEditorWindow, @result)) ElevatorEditor_HandleResult(@result);
	ElevatorEditor_DrawPlacementOverlays(canvas, play);
	ElevatorEditor_DrawMousePreview(canvas, play);
}

string ElevatorEditor_HelpText()
{
	return ELEVATOR_HELP_TEXT;
}

void ElevatorEditor_DrawTool(jjCANVAS@ canvas, int x, int y, int tool, int color, const string &in label)
{
	if(tool == ELEVATOR_EDIT_ERASE || tool == ELEVATOR_EDIT_BACKGROUND_COMPONENT)
	{
		canvas.drawRectangle(x, y - 4, 24, 2, color, SPRITE::NORMAL);
		canvas.drawRectangle(x, y + 18, 24, 2, color, SPRITE::NORMAL);
		canvas.drawRectangle(x, y - 4, 2, 24, color, SPRITE::NORMAL);
		canvas.drawRectangle(x + 22, y - 4, 2, 24, color, SPRITE::NORMAL);
	}
	else canvas.drawRectangle(x, y - 4, 24, 24, color, SPRITE::TRANSLUCENT);
	DbAddControl(@ElevatorEditorWindow, x, y - 4, 24, 24, ELEVATOR_EDITOR_ACT_SELECT, tool, 0, label);
	if(ElevatorEditorSelectedTool == tool) canvas.drawRectangle(x, y - 4, 24, 24, 15, SPRITE::TRANSLUCENT);
	ElevatorEditor_DrawWrappedLabel(canvas, x + 36, y, ElevatorEditorWindow.x + ElevatorEditorWindow.w - ElevatorEditorWindow.pad - x - 36, label);
}

void ElevatorEditor_DrawWrappedLabel(jjCANVAS@ canvas, int x, int y, int w, const string &in text)
{
	array<string> words = text.split(" ");
	string line = "";
	int lines = 0;
	for(uint i = 0; i < words.length && lines < 2; i++)
	{
		string candidate = line == "" ? words[i] : line + " " + words[i];
		if(jjGetStringWidth(candidate, STRING::SMALL, STRING::NORMAL) <= w) line = candidate;
		else
		{
			if(line != "")
			{
				canvas.drawString(x, y + lines * 12, line, STRING::SMALL, STRING::NORMAL);
				lines++;
			}
			line = words[i];
		}
	}
	if(line != "" && lines < 2) DbDrawWrappedSmallInBox(canvas, x, y + lines * 12, line, w, 12, 12);
}

void ElevatorEditor_DrawFocus(jjCANVAS@ canvas)
{
	DbNormalizeFocus(@ElevatorEditorWindow);
	if(ElevatorEditorWindow.focusIndex < 0 || ElevatorEditorWindow.focusIndex >= int(ElevatorEditorWindow.controls.length)) return;
	DbControl control = ElevatorEditorWindow.controls[ElevatorEditorWindow.focusIndex];
	if(!control.enabled) return;
	if(control.action == ELEVATOR_EDITOR_ACT_SELECT && ElevatorEditorSelectedTool != control.a) return;
	if(control.action == ELEVATOR_EDITOR_ACT_SELECT) canvas.drawRectangle(control.x, control.y + DB_FOCUS_OFFSET_Y, control.w, control.h, ElevatorEditorWindow.focusColor, SPRITE::TRANSLUCENT);
	else canvas.drawRectangle(control.x, control.y + DB_FOCUS_OFFSET_Y, control.w, control.h, ElevatorEditorWindow.focusColor, SPRITE::TRANSLUCENT);
}

void ElevatorEditor_HandleResult(DbResult@ result)
{
	if(result.closeRequested) { ElevatorEditor_Close(); return; }
	if(result.action == ELEVATOR_EDITOR_ACT_PREV || result.action == ELEVATOR_EDITOR_ACT_NEXT)
	{
		ElevatorEditorSelectedId = ElevatorEditor_CycleExistingId(ElevatorEditorSelectedId, result.b);
		ElevatorEditor_LoadSelectedOptions();
	}
	else if(result.action == ELEVATOR_EDITOR_ACT_ADD)
	{
		int next = ElevatorEditor_FindNextFreeId();
		if(next > 0) ElevatorEditorSelectedId = next;
		else jjAlert("No free elevator ids. Valid ids are 1-15.");
		ElevatorEditor_LoadSelectedOptions();
	}
	else if(result.action == ELEVATOR_EDITOR_ACT_DELETE)
	{
		ElevatorEditor_DeleteElevator(ElevatorEditorSelectedId);
		ElevatorEditorSelectedId = ElevatorEditor_FirstExistingId();
		ElevatorEditor_LoadSelectedOptions();
	}
	else if(result.action == ELEVATOR_EDITOR_ACT_SELECT)
	{
		ElevatorEditorSelectedTool = ElevatorEditorSelectedTool == result.a ? ELEVATOR_EDIT_NONE : result.a;
	}
	else if(result.action == ELEVATOR_EDITOR_ACT_HELP)
	{
		ElevatorEditorHelp = true;
		ElevatorEditorHelpScroll = 0;
	}
	else if(result.action == ELEVATOR_EDITOR_ACT_BACK)
	{
		ElevatorEditorHelp = false;
	}
	else if(DbIsScrollResult(result, ELEVATOR_EDITOR_ACT_HELP_SCROLL_UP, ELEVATOR_EDITOR_ACT_HELP_SCROLL_DOWN))
	{
		ElevatorEditorHelpScroll = DbHandleScrollResult(result, ElevatorEditorHelpScroll, ELEVATOR_EDITOR_ACT_HELP_SCROLL_UP, ELEVATOR_EDITOR_ACT_HELP_SCROLL_DOWN);
		return;
	}
	else if(result.action == ELEVATOR_EDITOR_ACT_SAVE)
	{
		Elevator_SavePlacements();
		ElevatorEditorDirty = false;
	}
	else if(result.action == ELEVATOR_EDITOR_ACT_CONTROL_MODE)
	{
		ElevatorEditorControlMode += result.b;
		if(ElevatorEditorControlMode < ELEVATOR_CONTROL_UP_DOWN) ElevatorEditorControlMode = ELEVATOR_CONTROL_ALL;
		if(ElevatorEditorControlMode > ELEVATOR_CONTROL_ALL) ElevatorEditorControlMode = ELEVATOR_CONTROL_UP_DOWN;
		ElevatorEditor_ApplySelectedOptions();
	}
	else if(result.action == ELEVATOR_EDITOR_ACT_ELEVATOR_TYPE)
	{
		ElevatorEditorElevatorType = ElevatorEditorElevatorType == ELEVATOR_TYPE_NORMAL ? ELEVATOR_TYPE_INVERSED : ELEVATOR_TYPE_NORMAL;
		ElevatorEditor_ApplySelectedOptions();
	}
	else if(result.action == ELEVATOR_EDITOR_ACT_SPEED)
	{
		ElevatorEditorSpeed = Elevator_ClampSpeed(ElevatorEditorSpeed + result.b);
		ElevatorEditor_ApplySelectedOptions();
	}
}

string ElevatorEditor_ControlModeText(int controlMode)
{
	if(controlMode == ELEVATOR_CONTROL_LEFT_RIGHT) return "Left/Right";
	if(controlMode == ELEVATOR_CONTROL_ALL) return "All";
	return "Up/Down";
}

string ElevatorEditor_TypeText(int elevatorType)
{
	return elevatorType == ELEVATOR_TYPE_INVERSED ? "Downward" : "Upward";
}

void ElevatorEditor_LoadSelectedOptions()
{
	Elevator_LoadEditorPlacements();
	ElevatorEditorControlMode = ELEVATOR_CONTROL_UP_DOWN;
	ElevatorEditorElevatorType = ELEVATOR_TYPE_NORMAL;
	ElevatorEditorSpeed = ELEVATOR_DEFAULT_SPEED;
	for(uint i = 0; i < ElevatorPlacements.length; i++)
	{
		if(ElevatorPlacements[i].id != ElevatorEditorSelectedId) continue;
		ElevatorEditorControlMode = ElevatorPlacements[i].controlMode;
		ElevatorEditorElevatorType = ElevatorPlacements[i].elevatorType;
		ElevatorEditorSpeed = Elevator_ClampSpeed(ElevatorPlacements[i].elevatorSpeed);
		return;
	}
}

void ElevatorEditor_ApplySelectedOptions()
{
	Elevator_LoadEditorPlacements();
	bool changed = false;
	for(uint i = 0; i < ElevatorPlacements.length; i++)
	{
		if(ElevatorPlacements[i].id != ElevatorEditorSelectedId) continue;
		ElevatorPlacements[i].controlMode = ElevatorEditorControlMode;
		ElevatorPlacements[i].elevatorType = ElevatorEditorElevatorType;
		ElevatorPlacements[i].elevatorSpeed = Elevator_ClampSpeed(ElevatorEditorSpeed);
		changed = true;
	}
	if(changed) ElevatorEditorDirty = true;
}

int ElevatorEditor_FindNextFreeId()
{
	for(int id = 1; id < ELEVATOR_MAX_ID; id++)
		if(!ElevatorEditor_IdExists(id)) return id;
	return -1;
}

int ElevatorEditor_FirstExistingId()
{
	Elevator_LoadEditorPlacements();
	for(int id = 1; id < ELEVATOR_MAX_ID; id++)
		if(Elevator_PlacementIdExists(id)) return id;
	return 1;
}

int ElevatorEditor_CycleExistingId(int currentId, int delta)
{
	Elevator_LoadEditorPlacements();
	array<bool> used(ELEVATOR_MAX_ID, false);
	for(uint i = 0; i < ElevatorPlacements.length; i++)
	{
		int id = ElevatorPlacements[i].id;
		if(id > 0 && id < ELEVATOR_MAX_ID) used[id] = true;
	}
	if(currentId > 0 && currentId < ELEVATOR_MAX_ID) used[currentId] = true;
	int count = 0;
	for(int id = 1; id < ELEVATOR_MAX_ID; id++)
		if(used[id]) count++;
	if(count <= 0) return 1;
	int id = currentId;
	for(int attempts = 0; attempts < ELEVATOR_MAX_ID; attempts++)
	{
		id += delta;
		if(id < 1) id = ELEVATOR_MAX_ID - 1;
		if(id >= ELEVATOR_MAX_ID) id = 1;
		if(used[id]) return id;
	}
	return currentId;
}

bool ElevatorEditor_IdExists(int id)
{
	Elevator_LoadEditorPlacements();
	return Elevator_PlacementIdExists(id);
}

bool ElevatorEditor_TileHasElevatorId(int x, int y, int id)
{
	int eventId = jjEventGet(x, y);
	if(platformObjects.find(eventId) < 0) return false;
	return jjParameterGet(x, y, 8, 4) == id;
}

void ElevatorEditor_DeleteElevator(int id)
{
	Elevator_LoadEditorPlacements();
	if(Elevator_RemovePlacementId(id))
	{
		ElevatorEditorDirty = true;
	}
}

void ElevatorEditor_ProcessTileClick()
{
	if(ElevatorEditorSelectedTool == ELEVATOR_EDIT_NONE) return;
	bool mouseDown = jjKey[0x01];
	if(!mouseDown) { ElevatorEditorMouseWasDown = false; return; }
	if(ElevatorEditorMouseWasDown || jjGameTicks < ElevatorEditorLastClick + 12) return;
	ElevatorEditorMouseWasDown = true;
	ElevatorEditorLastClick = jjGameTicks;
	int tileX, tileY;
	if(!ElevatorEditor_MouseTile(tileX, tileY)) return;
	if(DbPointIn(jjMouseX, jjMouseY + 8, ElevatorEditorWindow.x, ElevatorEditorWindow.y, ElevatorEditorWindow.w, ElevatorEditorWindow.h)) return;
	ElevatorEditor_PlaceTool(tileX, tileY);
}

bool ElevatorEditor_MouseTile(int &out tileX, int &out tileY)
{
	jjPLAYER@ play = jjLocalPlayers[0];
	tileX = int((play.cameraX + jjMouseX) / 32);
	tileY = int((play.cameraY + jjMouseY) / 32);
	return tileX >= 0 && tileY >= 0 && tileX < jjLayerWidth[4] && tileY < jjLayerHeight[4];
}

void ElevatorEditor_PlaceTool(int x, int y)
{
	Elevator_LoadEditorPlacements();
	if(ElevatorEditorSelectedTool == ELEVATOR_EDIT_ERASE)
	{
		if(Elevator_RemovePlacement(x, y))
		{
			ElevatorEditorDirty = true;
		}
		return;
	}
	if(ElevatorEditorSelectedTool == ELEVATOR_EDIT_LIMIT)
	{
		Elevator_SetPlacement(x, y, OBJECT::THING, 0, 0, ElevatorEditorSelectedId, 0, ElevatorEditorControlMode, ElevatorEditorElevatorType, ElevatorEditorSpeed);
		ElevatorEditorDirty = true;
		return;
	}
	int eventId = ElevatorEditorSelectedTool == ELEVATOR_EDIT_BOLL ? OBJECT::BOLLPLATFORM : OBJECT::PINKPLATFORM;
	int foreground = ElevatorEditorSelectedTool == ELEVATOR_EDIT_BACKGROUND_COMPONENT ? 1 : 0;
	int controllable = ElevatorEditorSelectedTool == ELEVATOR_EDIT_CONTROLLABLE ? 1 : 0;
	int speed = (ElevatorEditorSelectedTool == ELEVATOR_EDIT_COMPONENT || ElevatorEditorSelectedTool == ELEVATOR_EDIT_BACKGROUND_COMPONENT || ElevatorEditorSelectedTool == ELEVATOR_EDIT_BOLL) ? 0 : 1;
	Elevator_SetPlacement(x, y, eventId, foreground, speed, ElevatorEditorSelectedId, controllable, ElevatorEditorControlMode, ElevatorEditorElevatorType, ElevatorEditorSpeed);
	ElevatorEditorDirty = true;
}

int ElevatorEditor_PlacementColor(ElevatorSavedEvent &in placement)
{
	if(placement.eventId == OBJECT::THING) return 24;
	if(placement.eventId == OBJECT::BOLLPLATFORM) return 48;
	if(placement.speed == 0) return 64;
	if(placement.controllable == 1) return 32;
	return 80;
}

void ElevatorEditor_DrawPlacementOverlays(jjCANVAS@ canvas, jjPLAYER@ play)
{
	if(!ElevatorEditorOpen || ElevatorEditorHelp) return;
	Elevator_LoadEditorPlacements();
	for(uint i = 0; i < ElevatorPlacements.length; i++)
	{
		ElevatorSavedEvent placement = ElevatorPlacements[i];
		int screenX = placement.x * 32 - int(play.cameraX);
		int screenY = placement.y * 32 - int(play.cameraY);
		if(screenX < -32 || screenY < -32 || screenX > jjResolutionWidth || screenY > jjResolutionHeight) continue;
		int color = ElevatorEditor_PlacementColor(placement);
		if(placement.foreground == 1)
		{
			canvas.drawRectangle(screenX, screenY, 32, 2, color, SPRITE::NORMAL);
			canvas.drawRectangle(screenX, screenY + 30, 32, 2, color, SPRITE::NORMAL);
			canvas.drawRectangle(screenX, screenY, 2, 32, color, SPRITE::NORMAL);
			canvas.drawRectangle(screenX + 30, screenY, 2, 32, color, SPRITE::NORMAL);
		}
		else canvas.drawRectangle(screenX, screenY, 32, 32, color, SPRITE::TRANSLUCENT);
		ElevatorEditor_DrawPlacementId(canvas, screenX, screenY, placement.id);
	}
}

void ElevatorEditor_DrawPlacementId(jjCANVAS@ canvas, int x, int y, int id)
{
	string text = "" + id;
	int textW = jjGetStringWidth(text, STRING::SMALL, STRING::NORMAL);
	canvas.drawString(x + 16 - textW / 2, y + 12, text, STRING::SMALL, STRING::NORMAL);
}

void ElevatorEditor_DrawMousePreview(jjCANVAS@ canvas, jjPLAYER@ play)
{
	if(ElevatorEditorSelectedTool == ELEVATOR_EDIT_NONE || !ElevatorEditorOpen || ElevatorEditorHelp) return;
	int tileX, tileY;
	if(!ElevatorEditor_MouseTile(tileX, tileY)) return;
	int color = 32;
	if(ElevatorEditorSelectedTool == ELEVATOR_EDIT_AUTONOMOUS) color = 80;
	else if(ElevatorEditorSelectedTool == ELEVATOR_EDIT_COMPONENT || ElevatorEditorSelectedTool == ELEVATOR_EDIT_BACKGROUND_COMPONENT) color = 64;
	else if(ElevatorEditorSelectedTool == ELEVATOR_EDIT_BOLL) color = 48;
	else if(ElevatorEditorSelectedTool == ELEVATOR_EDIT_LIMIT) color = 24;
	else if(ElevatorEditorSelectedTool == ELEVATOR_EDIT_ERASE) color = 15;
	int screenX = tileX * 32 - int(play.cameraX);
	int screenY = tileY * 32 - int(play.cameraY);
	if(ElevatorEditorSelectedTool == ELEVATOR_EDIT_ERASE || ElevatorEditorSelectedTool == ELEVATOR_EDIT_BACKGROUND_COMPONENT)
	{
		canvas.drawRectangle(screenX, screenY, 32, 2, color, SPRITE::NORMAL);
		canvas.drawRectangle(screenX, screenY + 30, 32, 2, color, SPRITE::NORMAL);
		canvas.drawRectangle(screenX, screenY, 2, 32, color, SPRITE::NORMAL);
		canvas.drawRectangle(screenX + 30, screenY, 2, 32, color, SPRITE::NORMAL);
	}
	else canvas.drawRectangle(screenX, screenY, 32, 32, color, SPRITE::TRANSLUCENT);
}