Downloads containing academy_engine.asc

Downloads
Name Author Game Mode Rating
TSF with JJ2+ Only: Academy Superjazz Battle N/A Download file

File preview

#include "academy_drawing.asc"
#include "academy_drawing_general.asc"
#include "academy_entities.asc"
#include "academy_init.asc"
#include "academy_networking.asc"
#include "academy_spells.asc"
#include "academy_statics.asc"
#include "academy_utils.asc"
#include "sevk.asc"
#include "SEweapon.asc"
#pragma require "academy_drawing.asc"
#pragma require "academy_drawing_general.asc"
#pragma require "academy_entities.asc"
#pragma require "academy_init.asc"
#pragma require "academy_networking.asc"
#pragma require "academy_spells.asc"
#pragma require "academy_statics.asc"
#pragma require "academy_utils.asc"
#pragma require "sevk.asc"
#pragma require "SEweapon.asc"

/* Academy Engine, written by Superjazz of XLM */

bool demoModeOn = false;
bool debugModeOn = false;

bool channelingStarted = false;
bool delayFreeScroll = false;
bool isDuelLevel = false;
bool fullFeatures = true;
// A player can have chat open while the level cycles, there probably is no fix for this
bool inChatMode = false;
bool infoOpen = false;
bool hotkeyInUse = false;
bool recovering = false;
bool showResources = true;
bool skillsOpen = false;
bool spellBookOpen = false;

int channelingElapsed = 0;
int chatReleaseDelay = 0;
int freeScrollDelay = 10;
int hintBoxY = 0;
int hotkeyCycleSpells = 67; //112 = F1
int hotkeyInfo = 73;
int hotkeyKeyMenu = 75;
int hotkeyResources = 82;
int hotkeySkills = 76;
int hotkeySpellbook = 83;
int infoScrollY = 0;
int keyMenuState = 1;
int numpadElapsed = 0;
int selectionHotkey = -1;
int recoverElapsed = 0;
int secondarySkillCost = SECONDARY_SKILL_BASE_COST;

uint infoBoxHintPage = 0;

dictionary spells = {};

array<string> keyBindings;
array<string> ownSpells;
array<string> learnableSpells;
array<uint> numpadBuffer;
array<uint> numpadKeys = {96, 97, 98, 99, 100, 101, 102, 103, 104, 105};

array<array<Chunk>> chunks;

array<Key> keys(256);

array<Player> players(32);

array<AreaOfEffect@> activeAreasOfEffect;

array<array<ChainLightningTarget@>> chainLightningTargetGroups;

array<GemMine@> gemMines;

array<MagicMirrorAnimation@> magicMirrorAnimations;

array<WallOfFire@> activeWallsOfFire;

namespace acEngine {
	
	void controlActiveAreasOfEffect(jjPLAYER@ play) {
		int j = 0;
		int activeAreasOfEffectLength = activeAreasOfEffect.length();
		for (int i = 0; i < activeAreasOfEffectLength; i++) {
			AreaOfEffect@ aoe = activeAreasOfEffect[i];
			aoe.animate();
			aoe.control(play);
			if (aoe.elapsed > 0) {
				aoe.elapsed--;
				@activeAreasOfEffect[j] = aoe;
				j++;
			}
		}
		activeAreasOfEffect.removeRange(j, activeAreasOfEffectLength - j);
	}
	
	void controlActiveEffects(jjPLAYER@ play, Player@ asPlayer) {
		if (asPlayer.activeEffects.length() >= 1) {
			for (uint i = 0; i < asPlayer.activeEffects.length(); i++) {
				jjTEXTAPPEARANCE centeredText();
				centeredText.align = STRING::CENTER;
				
				Effect@ effect = asPlayer.activeEffects[i];
				
				jjDrawString(play.xPos, play.yPos + EFFECT_INITIAL_HEIGHT + i * ROW_SPACING,
						effect.name + " " + int(effect.elapsed / SECOND), STRING::SMALL, centeredText, 0,
						SPRITE::PALSHIFT, 0, 1);
				
				if (acUtils::gameIsRunning()) {
					if (effect.elapsed > 0) {
						effect.elapsed--;
						if ((play.isLocal && effect.isLocal) || (jjIsServer && !effect.isLocal)) {
							effect.affect();
						}
					} else {
						asPlayer.removeActiveEffect(i);
						acSpells::unDoEffect(play.playerID);
					}
				}
			}
		}
	}

	void controlActiveWallsOfFire(jjPLAYER@ play) {
		int j = 0;
		int activeWallsOfFireLength = activeWallsOfFire.length();
		for (int i = 0; i < activeWallsOfFireLength; i++) {
			WallOfFire@ wallOfFire = activeWallsOfFire[i];
			acDrawing::drawWallOfFire(wallOfFire);
			if (acUtils::gameIsRunning()) {
				float adjustedXOrigin = wallOfFire.xOrigin - TILE;
				float adjustedYOrigin = wallOfFire.yOrigin + TILE;
				float adjustedWidth = (WALL_OF_FIRE_WIDTH + 1) * TILE;
				float adjustedHeight = (wallOfFire.height + 2) * TILE;
				
				array<float> hitBox = {adjustedXOrigin, adjustedYOrigin,
						adjustedXOrigin+adjustedWidth, adjustedYOrigin-adjustedHeight};
						
				if (play.xPos >= hitBox[0] && play.xPos <= hitBox[2] &&
						play.yPos <= hitBox[1] && play.yPos >= hitBox[3]) {
					play.hurt(wallOfFire.damage - players[play.playerID].magicResist, false, wallOfFire.caster);
				}
				if (wallOfFire.elapsed > 0) {
					wallOfFire.elapsed--;
				}
			}
			if (wallOfFire.elapsed > 0) {
				@activeWallsOfFire[j] = wallOfFire;
				j++;
			}
		}
		activeWallsOfFire.removeRange(j, activeWallsOfFireLength - j);
	}
	
	void controlChat(int clientID, string &in received, CHAT::Type type) {
		if (jjIsServer) {
			array<jjPLAYER@> players = jjPlayersWithClientID(clientID);
			if (players.length() >= 1 && (players[0].isLocal || players[0].isAdmin) && type == CHAT::NORMAL) {
				if (jjRegexMatch(received.substr(0, 9), "!demomode.*", true)) {
					string choice = received.substr(9);
					if (jjRegexMatch(choice, "\\s*on\\s*", true)) {
						demoModeOn = true;
						ownSpells = acInit::loadSpells();
						acNetworking::sendDemoModeData(0);
						jjAlert("Demo mode has been turned on!", true);
					} else if (jjRegexMatch(choice, "\\s*off\\s*", true)) {
						demoModeOn = false;
						acUtils::disableDemoMode();
						acNetworking::sendDemoModeData(0);
						jjAlert("Demo mode has been turned off!", true);
					}
				}
			}
		}
	}
	
	void controlCycleSpellsInput(Player@ asPlayer) {
		if (jjKey[hotkeyCycleSpells] && !keys[hotkeyCycleSpells].keyPressed && ownSpells.length() > 0) {
			int index = acSpells::getSpellIndexByKey(asPlayer.selectedSpellKey);
			if (index == -1) {
				Spell@ spell = cast<Spell@>(spells[ownSpells[0]]);
				asPlayer.setSelectedSpellKey(spell.key);
			} else if (index >= 0) {
				if (index >= int(ownSpells.length()) - 1) {
					asPlayer.unSetChanneledSpellKey();
				} else {
					while (index < int(ownSpells.length() - 2) && ownSpells[index] == ownSpells[index+1]) {
						index++;
						if (debugModeOn) {
							jjAlert("ownSpells[index]: " + ownSpells[index]);
							jjAlert("ownSpells[index+1]: " + ownSpells[index+1]);
							jjAlert("index: " + index);
						}
					}
					Spell@ nextSpell = cast<Spell@>(spells[ownSpells[index+1]]);
					asPlayer.setSelectedSpellKey(nextSpell.key);
				}
			}
			acUtils::closeOtherBoxes(BOX_SPELL_BOOK, null);
		}
	}
	
	void controlElevatorTileInput(jjPLAYER@ play) {
		int elevatorTileX = isDuelLevel ? ELEVATOR_TILE_X_DUEL : ELEVATOR_TILE_X;
		int elevatorTileY = isDuelLevel ? ELEVATOR_TILE_Y_DUEL : ELEVATOR_TILE_Y;
		if (selectionHotkey < 0 && play.keyUp
				&& int(play.xPos/TILE) == elevatorTileX && int(play.yPos/TILE) == elevatorTileY) {
			play.warpToID(0, true);
		}
	}
	
	void controlChatMode() {
		if (jjKey[HOTKEY_CHAT] && !inChatMode) {
			inChatMode = true;
		} else if (inChatMode &&
				(jjKey[getKeyCodeByName("Enter")]
				|| jjKey[getKeyCodeByName("Esc")])) {
			chatReleaseDelay = CHAT_RELEASE_DELAY;
		}
		if (chatReleaseDelay > 0) chatReleaseDelay--;
	}
	
	void controlInfoMenuInput(jjPLAYER@ play, Player@ asPlayer) {
		if (selectionHotkey < 0 && !infoOpen && !keys[hotkeyInfo].keyPressed && jjKey[hotkeyInfo]) {
			infoOpen = true;
			acUtils::closeOtherBoxes(BOX_INFO, asPlayer);
		} else if (selectionHotkey < 0 && infoOpen && jjKey[1] && !keys[1].keyPressed
				&& acUtils::mouseIsInSelection(jjSubscreenWidth - 256, hintBoxY + HINT_BOX_HEIGHT - 16, 256, 16)) {
			if (infoBoxHintPage < infoBoxHints.length() - 1) infoBoxHintPage++;
			else infoBoxHintPage = 0;
		} else if (infoOpen && (play.keyFire || (!keys[hotkeyInfo].keyPressed && jjKey[hotkeyInfo]))) {
			infoOpen = false;
		}
	}
	
	void controlInfoScrolling(jjPLAYER@ play) {
		if (jjMouseX >= 0 && jjMouseY >= 0 && jjMouseX <= jjSubscreenWidth && jjMouseY <= jjSubscreenHeight) {
			if ((jjMouseY <= SPELL_BOXES_INIT_Y + 32 || play.keyUp) && infoScrollY < 0) {
				infoScrollY += INFO_SCROLL_SPEED;
			} else if ((jjMouseY >= jjSubscreenHeight / 10 * 9 || play.keyDown) && acUtils::infoViewIsAboveBottom()) {
				infoScrollY -= INFO_SCROLL_SPEED;
			}
		}
	}
	
	void controlKeyMenuInput(Player@ asPlayer) {
		if (selectionHotkey < 0 && keyMenuState == 2 && ((jjKey[hotkeyKeyMenu] && !keys[hotkeyKeyMenu].keyPressed) ||
				(jjKey[1] && acUtils::mouseIsOutsideKeyMenu()))) {
			keyMenuState = 0;
			selectionHotkey = -1;
		} else if (keyMenuState == 2 && jjKey[1] && acUtils::mouseIsWithinKeyMenuChoices()) {
			jjTEXTAPPEARANCE centeredText;
			centeredText.align = STRING::CENTER;
			for (uint i = 0; i < keyBindings.length(); i++) {
				string keyBinding = keyBindings[i];
				int stringWidth = jjGetStringWidth(keyBinding, STRING::SMALL, centeredText);
				if (jjMouseX < jjSubscreenWidth / 2 + stringWidth / 2 && jjMouseX > jjSubscreenWidth / 2 - stringWidth / 2
						&& jjMouseY >= jjSubscreenHeight / 4 + 102 + i*16 && jjMouseY < jjSubscreenHeight / 4 + 102 + (i+1)*16) {
					selectionHotkey = int(i);
				}
			}
		} else if (selectionHotkey < 0 && keyMenuState == 1 && jjKey[hotkeyKeyMenu] && !keys[hotkeyKeyMenu].keyPressed) {
			hotkeyInUse = false;
			keyMenuState = 2;
			acUtils::closeOtherBoxes(BOX_KEY_MENU, asPlayer);
		} else if (selectionHotkey < 0 && jjKey[hotkeyKeyMenu] && !keys[hotkeyKeyMenu].keyPressed) {
			hotkeyInUse = false;
			keyMenuState = 1;
		}
	}
	
	void controlMain() {
		for (uint y = 0; y < chunks.length(); y++) {
			for (uint x = 0; x < chunks[y].length(); x++) {
				chunks[y][x].clearObjects();
			}
		}
		for (int i = 0; i < jjObjectCount; i++) {
			jjOBJ@ obj = jjObjects[i];
			uint yChunk = uint(obj.yPos) >> 7;
			uint xChunk = uint(obj.xPos) >> 7;
			if (obj.isActive && yChunk < chunks.length() && xChunk < chunks[yChunk].length()) {
				chunks[yChunk][xChunk].addObject(obj);
			}
		}
		for (uint i = 0; i < players.length(); i++) {
			jjPLAYER@ play = jjPlayers[i];
			Player@ asPlayer = players[i];
			controlActiveEffects(play, asPlayer);
			if (asPlayer.isChanneling) {
				acDrawing::drawAreaOfEffect(play, cast<Spell@>(spells[asPlayer.selectedSpellKey]).radius);
				if (asPlayer.selectedSpellKey == "L") {
					acDrawing::drawChainLightningTargets(play);
				} else if (asPlayer.selectedSpellKey == "I") {
					acDrawing::drawWallOfFireTarget(play);
				}
			}
		}
		if (numpadBuffer.length() > 0) {
			if (numpadElapsed > 0) {
				numpadElapsed--;
			} else {
				numpadBuffer.removeRange(0, numpadBuffer.length());
			}
		}
	}
	
	void controlNumpadKey(uint index, uint i, Player@ asPlayer) {
		if (!keys[index].keyPressed && jjKey[index]) {
			if (i == 0 && numpadBuffer.length() < 1) {
				asPlayer.unSetChanneledSpellKey();
			} else {
				if (numpadBuffer.length() >= 1) {
					array<uint> buffer = {numpadBuffer[0], i};
					int numpadIndex = acUtils::parseNumpadIndex(buffer);
					string spellKey = acUtils::getSpellKeyByNumpadIndex(uint(numpadIndex));
					if (numpadBuffer.length() >= 2 || (numpadIndex >= 1 && ownSpells.find(spellKey) < 0)) {
						numpadBuffer.removeRange(0, numpadBuffer.length());
					}
				}
				numpadElapsed = NUMPAD_BUFFER_TIME;
				numpadBuffer.insertLast(i);
				int numpadIndex = acUtils::parseNumpadIndex(numpadBuffer);
				if (debugModeOn) jjAlert("numpadIndex: " + numpadIndex);
				if (numpadIndex >= 1) {
					string spellKey = acUtils::getSpellKeyByNumpadIndex(uint(numpadIndex));
					if (ownSpells.find(spellKey) >= 0) {
						channelingElapsed = 0;
						asPlayer.setSelectedSpellKey(spellKey);
					} else {
						numpadBuffer.removeRange(0, numpadBuffer.length());
					}
					acUtils::closeOtherBoxes(BOX_SPELL_BOOK, null);
				} else {
					asPlayer.unSetChanneledSpellKey();
				}
			}
		}
	}

	void controlNumpadKeys(Player@ asPlayer) {
		for (uint i = 0; i < numpadKeys.length(); i++) {
			uint index = numpadKeys[i];
			controlNumpadKey(index, i, asPlayer);
		}
	}
	
	void controlPlayer(jjPLAYER@ play) {
		Player@ asPlayer = players[play.playerID];
		play.noFire = (players[play.playerID].selectedSpellKey != "" ||
				players[play.playerID].hasEffect(SPELL_FORGETFULNESS));
		if (recovering) {
			if (recoverElapsed < 35) {
				play.noFire = true;
				recoverElapsed++;
			} else {
				recovering = false;
				recoverElapsed = 0;
			}
		}
		if (acUtils::gameIsRunning()) {
			asPlayer.regenerateMana(play);
			if (asPlayer.cooldown > 0) {
				asPlayer.cooldown--;
			}
		}
		acDrawing::drawBulletPointer(play, asPlayer);
		controlActiveWallsOfFire(play);
		controlActiveAreasOfEffect(play);
		controlPlayerAssets(play, asPlayer);
		acDrawing::drawChainLightnings();
		acDrawing::drawMagicMirrorAnimations();
		for (uint i = 0; i < gemMines.length(); i++) {
			gemMines[i].control(play, asPlayer);
		}
		if ((play.health <= 0 || !play.isInGame) && !asPlayer.isDead) {
			asPlayer.isDead = true;
			acNetworking::sendPlayerDeadPacket(play.playerID);
			if (jjIsServer) {
				doDeadPlayer(play.playerID);
			}
		} else if (play.health > 0) {
			asPlayer.isDead = false;
		}
		if (infoOpen) controlInfoScrolling(play);
	}
	
	void controlPlayerAssets(jjPLAYER@ play, Player@ asPlayer) {
		string firstLearnableSpellKey = acUtils::getFirstLearnableSpell();
		if (firstLearnableSpellKey.length() > 0) {
			Spell@ learnableSpell = cast<Spell@>(spells[firstLearnableSpellKey]);
			int spellPrice = acUtils::getSpellPriceByTier(learnableSpell.tier);
			if (play.coins >= spellPrice && play.testForCoins(spellPrice)) {
				ownSpells.insertLast(learnableSpell.key);
				ownSpells = acUtils::sortSpellKeys(ownSpells);
				if (jjIsServer) {
					acUtils::alertOfLearnedSpell(play.nameUnformatted, learnableSpell.name);
				} else {
					acNetworking::sendSpellLearnedPacket(play.playerID, firstLearnableSpellKey);
				}
				string nextLearnableSpellKey = acUtils::getFirstLearnableSpell();
				if (nextLearnableSpellKey.length() > 0) {
					Spell@ nextLearnableSpell = cast<Spell@>(spells[nextLearnableSpellKey]);
					spellPrice = acUtils::getSpellPriceByTier(nextLearnableSpell.tier);
					jjAlert("To learn the next spell ("
							+ nextLearnableSpell.name + "), gather "+ spellPrice + " coins.");
				} else {
					jjAlert("You have learned all the spells! Use your full powers upon thy enemies!");
				}
			}
		}
		if (asPlayer.activeSkills.length() < skills.length()
				&& play.gems[GEM::PURPLE] >= secondarySkillCost
				&& play.testForGems(secondarySkillCost, GEM::PURPLE)) {
			secondarySkillCost += SECONDARY_SKILL_EXTRA_COST;
			asPlayer.addNewRandomSkill(play.nameUnformatted);
			if (asPlayer.activeSkills.length() < skills.length()) {
				jjAlert("To learn the next secondary skill (by random), gather " + secondarySkillCost + " purple gems.");
			} else {
				jjAlert("You have learned all the secondary skills!");
			}
		}
	}
	
	void controlPlayerInput(jjPLAYER@ play) {
		Player@ asPlayer = players[play.playerID];
		// controlChatMode has to be the first one
		controlChatMode();
		if (chatReleaseDelay <= 0) {
			controlElevatorTileInput(play);
			controlKeyMenuInput(asPlayer);
			controlResourceTabInput();
			controlCycleSpellsInput(asPlayer);
			controlInfoMenuInput(play, asPlayer);
			controlNumpadKeys(asPlayer);
			controlSelectionOfHotkeys();
			controlSkillsMenuInput(asPlayer);
			controlSpellbookInput(asPlayer);
			controlSpellCastingInput(play, asPlayer);
		}
		// controlPressedKeys has to be the last one
		controlPressedKeys();
	}
	
	void controlPressedKeys() {
		for (uint i = 0; i < 256; i++) {
			if (@keys[i] != null) {
				keys[i].keyPressed = jjKey[i];
			}
		}
	}
	
	void controlResourceTabInput() {
		if (!showResources && jjKey[hotkeyResources] && !keys[hotkeyResources].keyPressed) {
			showResources = true;
		} else if (jjKey[hotkeyResources] && !keys[hotkeyResources].keyPressed) {
			showResources = false;
		}
	}
	
	void controlSelectionOfHotkeys() {
		if (selectionHotkey >= 0 && !jjKey[1]) {
			for (uint i = 0; i < 256; i++) {
				if (jjKey[i]) {
					acUtils::setHotkey(selectionHotkey, i);
					selectionHotkey = -1;
					break;
				}
			}
		}
	}
	
	void controlSkillsMenuInput(Player@ asPlayer) {
		if (selectionHotkey < 0 && !skillsOpen && !keys[hotkeySkills].keyPressed && jjKey[hotkeySkills]) {
			skillsOpen = true;
			acUtils::closeOtherBoxes(BOX_SKILLS, asPlayer);
		} else if (skillsOpen && !keys[hotkeySkills].keyPressed && jjKey[hotkeySkills]) {
			skillsOpen = false;
		}
	}
	
	void controlSpellbookInput(Player@ asPlayer) {
		if (selectionHotkey < 0 && !spellBookOpen && !keys[hotkeySpellbook].keyPressed && jjKey[hotkeySpellbook]) {
			spellBookOpen = true;
			acUtils::closeOtherBoxes(BOX_SPELL_BOOK, asPlayer);
		} else if (spellBookOpen && !keys[hotkeySpellbook].keyPressed && jjKey[hotkeySpellbook]) {
			spellBookOpen = false;
		}
	}
	
	void controlSpellCastingInput(jjPLAYER@ play, Player@ asPlayer) {
		if (asPlayer.selectedSpellKey == "I" && activeWallsOfFire.length() >= MAX_ACTIVE_WALLS_OF_FIRE) {
			//Cannot cast
		} else if (play.isInGame && asPlayer.selectedSpellKey != "" && play.keyFire
				&& acSpells::canCastSpell(players[play.playerID], cast<Spell@>(spells[asPlayer.selectedSpellKey]))) {
			spellBookOpen = false;
			if (!channelingStarted) {
				channelingStarted = true;
				asPlayer.setChanneledSpellKey(asPlayer.selectedSpellKey);
				acNetworking::sendChannelingStartedPacket(play.playerID, cast<Spell@>(spells[asPlayer.selectedSpellKey]).enumValue);
			}
			acSpells::channel(play);
		} else if (asPlayer.selectedSpellKey != "" && !play.keyFire) {
			if (channelingStarted) {
				channelingStarted = false;
				asPlayer.isChanneling = false;
				if (!demoModeOn) {
					Spell@ spell = cast<Spell@>(spells[asPlayer.selectedSpellKey]);
					asPlayer.cooldown = spell.tier * SECOND;
				}
				acNetworking::sendChannelingStoppedPacket(play.playerID);
				if (jjIsServer) {
					asPlayer.unSetChanneledSpellKey();
				}
			}
			channelingElapsed = 0.f;
		}
	}
	
	void doDeadPlayer(int8 playerID) {
		Player@ asPlayer = players[playerID];
		asPlayer.isChanneling = false;
		if (asPlayer.activeEffects.length() == 0) {
			asPlayer.originalFur = jjPlayers[playerID].fur; //Make sure the original fur is saved
		} else {
			asPlayer.removeAllActiveEffects();
		}
		if (jjIsServer) acSpells::changePlayerFur(SPELL_UNDO, playerID);
	}
	
	bool doDrawAmmo(jjPLAYER@ play, jjCANVAS@ canvas) {
		return acDrawing::drawHUDObjects(play, canvas);
	}

	void doDrawLayer4(jjPLAYER@ play, jjCANVAS@ canvas) {
		acDrawing::drawLayer4(play, canvas);
	}
	
	void doGameStop() {
		players[jjLocalPlayers[0].playerID].cooldown = 0;
	}
	
	void doReceive(jjSTREAM &in packet, int clientID) {
		acNetworking::doReceive(packet, clientID);
	}
	
	void initialize(bool setFullFeatures = true, bool setDuelLevel = false) {
		fullFeatures = setFullFeatures;
		isDuelLevel = setDuelLevel;
		spells = fullFeatures ? acSpells::fullSpells : acSpells::normalSpells;
		acInit::loadPlayerIDs();
		acInit::loadChunks();
		acInit::loadKeys();
		acInit::loadSprites();
		acInit::loadBullets();
		ownSpells = demoModeOn ? acInit::loadSpells() : acInit::loadSpells(LOWEST_TIER, HIGHEST_STARTING_TIER);
		learnableSpells = acInit::loadSpells(LOWEST_LEARNABLE_TIER, HIGHEST_TIER);
		acInit::loadOthers();
	}
	
	void initializeLevel() {
		jjSugarRushAllowed = true;
		if (!isDuelLevel) {
			gemMines.insertLast(GemMine(0, "Eastern", GEM_MINE_EAST_TOP, GEM_MINE_EAST_BOTTOM,
					GEM_MINE_EAST_LEFT, GEM_MINE_EAST_RIGHT));
			gemMines.insertLast(GemMine(1, "Western", GEM_MINE_WEST_TOP, GEM_MINE_WEST_BOTTOM,
					GEM_MINE_WEST_LEFT, GEM_MINE_WEST_RIGHT));
		}
		if (!jjIsServer) acNetworking::sendReqSyncDataPacket();
	}
}