Part 35: Teleporters
Downloads
Parameters of the teleporters
		<tile name="Teleporter">
			<image>Teleporter.png</image>
			<param type="int">Level</param>
			<param type="int">X</param>
			<param type="int">Y</param>
			<param type="enum" values="Up;Left;Down;Right;None">Side</param>
			<param type="bool">forChampions</param>
			<param type="bool">forObjects</param>
		</tile>
				
Graphics
 
				 
				 
				 
				 
				
		QImage  wallGfx = fileCache.getImage(fileName);
		CVec2   wallPos(tileInfo->x, tileInfo->y);
		QImage  teleportGfx = fileCache.getImage("gfx/3DView/Teleporter.png");
		// create the teleporter image
		QImage  tempImg(wallGfx.size(), QImage::Format_ARGB32);
		tempImg.fill(TRANSPARENT);
		int subImgX = (wallGfx.size().width() + teleportGfx.size().width() - 1) / teleportGfx.size().width();
		int subImgY = (wallGfx.size().height() + teleportGfx.size().height() - 1) / teleportGfx.size().height();
		[...]
		for (int y = 0; y < subImgY; ++y)
			for (int x = 0; x < subImgX; ++x)
			{
				CVec2   subImgPos(x * teleportGfx.size().width(),
				                  y * teleportGfx.size().height());
				[...]
				graph2D.drawImage(&tempImg, subImgPos, teleportGfx, angle, flip);
			}
		// darken
		int shadow = WALL_TABLE_HEIGHT - 2 - tablePos.y;
		if (shadow < 0)
			shadow = 0;
		graph2D.darken(&tempImg, (float)shadow * 0.2f);
		// draw the image
		graph2D.drawImageWithMask(image, wallPos, tempImg, wallGfx);
				
Animation
		int random = game.frameCounter / 20;
		[...]
			// create the teleporter image
			[...]
			random = (random * 31415821 + 1) % 100000000;
			for (int y = 0; y < subImgY; ++y)
				for (int x = 0; x < subImgX; ++x)
				{
					[...]
					bool flip = ((random & 1) != 0);
					int angle = ((random >> 1) % 4) * 90;
					graph2D.drawImage(&tempImg, subImgPos, teleportGfx, angle, flip);
				}
				
The whole tile
		struct STelepTile
		{
			char        file[16];
			uint16_t    x, y;
		};
		static const STelepTile   gTelepTiles[WALL_TABLE_HEIGHT][WALL_TABLE_WIDTH][3] =
		{
			// Row 3 (farthest)
			{
				{{"Wall02_F.png",   0, 58}, {"", 0, 0},                {"Wall13_L.png",  8, 58}}, // 02
				{{"Wall12_F.png",   7, 58}, {"", 0, 0},                {"Wall23_L.png", 78, 59}}, // 12
				{{"Wall22_F.png",  77, 58}, {"", 0, 0},                {"", 0, 0}              }, // 22
				{{"Wall32_F.png", 146, 58}, {"Wall23_R.png", 134, 59}, {"", 0, 0}              }, // 32
				{{"Wall42_F.png", 216, 58}, {"Wall33_R.png", 180, 58}, {"", 0, 0}              }  // 42
			},
			// Row 2
			{
				{{"", 0, 0},                {"", 0, 0},                {"Wall12_L.png",  0, 57}}, // 01
				{{"Wall11_F.png",   0, 52}, {"", 0, 0},                {"Wall22_L.png", 60, 52}}, // 11
				{{"Wall21_F.png",  59, 52}, {"", 0, 0},                {"", 0, 0}              }, // 21
				{{"Wall31_F.png", 164, 52}, {"Wall22_R.png", 146, 52}, {"", 0, 0}              }, // 31
				{{"", 0, 0},                {"Wall32_R.png", 216, 57}, {"", 0, 0}              }  // 41
			},
			// Row 1
			{
				{{"", 0, 0},                {"", 0, 0},                {"", 0, 0}              }, // 00
				{{"Wall10_F.png",   0, 42}, {"", 0, 0},                {"Wall21_L.png", 33, 42}}, // 10
				{{"Wall20_F.png",  32, 42}, {"", 0, 0},                {"", 0, 0}              }, // 20
				{{"Wall30_F.png", 191, 42}, {"Wall21_R.png", 164, 42}, {"", 0, 0}              }, // 30
				{{"", 0, 0},                {"", 0, 0},                {"", 0, 0}              }  // 40
			},
			// Row 0 (nearest)
			{
				{{"", 0, 0},                {"", 0, 0},                {"", 0, 0}             }, // 00
				{{"", 0, 0},                {"", 0, 0},                {"Wall20_L.png", 0, 33}}, // 10
				{{"Wall20_F.png",  32, 42}, {"Wall20_R.png", 191, 33}, {"Wall20_L.png", 0, 33}}, // 20
				{{"", 0, 0},                {"Wall20_R.png", 191, 33}, {"", 0, 0}             }, // 30
				{{"", 0, 0},                {"", 0, 0},                {"", 0, 0}             }  // 40
			}
		};
				
		void CTiles::drawTeleporter(QImage* image, CVec2 tablePos)
		{
			for (int i = 0; i < 3; ++i)
			{
				int random = game.frameCounter / 20;
				const STelepTile* tileInfo = &gTelepTiles[tablePos.y][tablePos.x][i];
				if (tileInfo->file[0] != 0)
				{
					static char fileName[256];
					sprintf(fileName, "gfx/3DView/walls/%s", tileInfo->file);
					QImage  wallGfx = fileCache.getImage(fileName);
					CVec2   wallPos(tileInfo->x, tileInfo->y);
					QImage  teleportGfx = fileCache.getImage("gfx/3DView/Teleporter.png");
					// create the teleporter image
					QImage  tempImg(wallGfx.size(), QImage::Format_ARGB32);
					tempImg.fill(TRANSPARENT);
					int subImgX = (wallGfx.size().width() + teleportGfx.size().width() - 1) / teleportGfx.size().width();
					int subImgY = (wallGfx.size().height() + teleportGfx.size().height() - 1) / teleportGfx.size().height();
					random = (random * 31415821 + 1) % 100000000;
					for (int y = 0; y < subImgY; ++y)
						for (int x = 0; x < subImgX; ++x)
						{
							CVec2   subImgPos(x * teleportGfx.size().width(),
							                  y * teleportGfx.size().height());
							bool flip = ((random & 1) != 0);
							int angle = ((random >> 1) % 4) * 90;
							graph2D.drawImage(&tempImg, subImgPos, teleportGfx, angle, flip);
						}
					// darken
					int shadow = WALL_TABLE_HEIGHT - 2 - tablePos.y;
					if (shadow < 0)
						shadow = 0;
					graph2D.darken(&tempImg, (float)shadow * 0.2f);
					// draw the image
					graph2D.drawImageWithMask(image, wallPos, tempImg, wallGfx);
				}
			}
		}
				
Stepping inside it
		void CPlayer::teleport()
		{
			CTile*  tile = map.getTile(pos);
			int     level = tile->getIntParam("Level");
			CVec2   newPos = CVec2(tile->getIntParam("X"), tile->getIntParam("Y"));
			int     side = tile->getEnumParam("Side");
			if (side == eWallSideMax)
				side = dir;
			if (level != game.currentLevel)
			{
				game.loadLevel(level, newPos, side);
			}
			else
			{
				player.pos = newPos;
				player.dir = side;
			}
			sound->play(player.pos, "sound/Buzz.wav");
			shouldTeleport = false;
		}
				
Dropping objects in it
            else if (clickedArea->type == eMouseAreaG_DropObject)
            {
                CVec2   pos = CVec2((int)clickedArea->param1, (int)clickedArea->param2);
                int side = (int)clickedArea->param3;
			    [... drop the object]
                if (side == eWallSideMax)
                {
                    CVec2   mapPos = pos / 2;
                    CTile*  tile = map.getTile(mapPos);
                    if (tile->getType() == eTileTeleporter && tile->getBoolParam("forObjects") == true)
                        teleportStacks(mapPos);
                }
            }
				
		void CGame::teleportStacks(CVec2 mapPos)
		{
			CTile*  tile = map.getTile(mapPos);
			std::vector<CObjectStack>   copyStacks;
			// copies the stacks
			for (int y = 0; y < 2; ++y)
				for (int x = 0; x < 2; ++x)
				{
					CVec2 objPos = mapPos * 2 + CVec2(x, y);
					CObjectStack*    stack = map.findObjectsStack(objPos, eWallSideMax);
					if (stack != NULL)
					{
						CObjectStack    copy = *stack;
						copy.mPos = CVec2(x, y);
						copyStacks.push_back(copy);
						map.removeObjectsStack(objPos, eWallSideMax);
					}
				}
				
			int     lastLevel = currentLevel;
			CVec2   lastPos = player.pos;
			uint8_t lastDir = player.dir;
			int     level = tile->getIntParam("Level");
			CVec2   newPos = CVec2(tile->getIntParam("X"), tile->getIntParam("Y"));
			// load destination level
			if (level != currentLevel)
				loadLevel(level, CVec2(), 0);
				
			// set the stacks at the new pos
			for (size_t i = 0; i < copyStacks.size(); ++i)
			{
				CVec2 objPos = newPos * 2 + copyStacks[i].mPos;
				CObjectStack*   stack = map.addObjectsStack(objPos, eWallSideMax);
				for (size_t j = 0; j < copyStacks[i].getSize(); ++j)
					stack->addObject(copyStacks[i].getObject(j));
			}
				
			// reload the last level
			if (level != lastLevel)
				loadLevel(lastLevel, lastPos, lastDir);
		}
				
Bugs fixed in the editor