1 /*
2 Copyright (C) 2007, 2010 - Bit-Blot
3 
4 This file is part of Aquaria.
5 
6 Aquaria is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
10 
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 
15 See the GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20 */
21 #include "DSQ.h"
22 #include "Game.h"
23 #include "Avatar.h"
24 #include "GridRender.h"
25 #include "Gradient.h"
26 #include "TTFFont.h"
27 #include "RoundedRect.h"
28 
29 #define GEM_GRAB			 10
30 
31 namespace WorldMapRenderNamespace
32 {
33 	const float WORLDMAP_UNDERLAY_ALPHA = 0.8;
34 
35 	float baseMapSegAlpha		= 0.4;
36 	float visibleMapSegAlpha	= 0.8;
37 
38 	const float blinkPeriod		= 0.2;
39 
40 	// Fraction of the screen width and height we consider "visited".
41 	// (We don't mark the entire screen "visited" because the player may
42 	// overlook things on the edge of the screen while moving.)
43 	const float visitedFraction	= 0.8;
44 
45 	enum VisMethod
46 	{
47 		VIS_VERTEX		= 0, // Uses the RenderObject tile grid (RenderObject::setSegs()) to display visited areas
48 		VIS_WRITE		= 1  // Uses render-to-texture instead
49 	};
50 
51 	const VisMethod visMethod = VIS_VERTEX;
52 	WorldMapRevealMethod revMethod = REVEAL_DEFAULT;
53 
54 	std::vector<Quad *> tiles;
55 
56 	Quad *activeQuad=0, *lastActiveQuad=0, *originalActiveQuad=0;
57 	Quad *lastVisQuad=0, *visQuad=0;
58 	WorldMapTile *lastVisTile=0;
59 
60 	float xMin, yMin, xMax, yMax;
61 
62 	float zoomMin = 0.2;
63 	float zoomMax = 3.0;
64 	const float exteriorZoomMax = 3.0;
65 	const float interiorZoomMax = 3.0;
66 
67 	bool editorActive=false;
68 
69 	Quad *tophud=0;
70 
71 	Gradient *underlay = 0;
72 }
73 
74 using namespace WorldMapRenderNamespace;
75 
76 std::vector <Quad*> grid;
77 
78 class GemMover;
79 
80 GemMover *mover=0;
81 
82 WorldMapTile *activeTile=0;
83 
84 const float beaconSpawnBitTime = 0.05;
85 
86 
setRevealMethod(WorldMapRevealMethod m)87 void WorldMapRender::setRevealMethod(WorldMapRevealMethod m)
88 {
89 	switch(m)
90 	{
91 		case REVEAL_PARTIAL:
92 			revMethod = REVEAL_PARTIAL;
93 			baseMapSegAlpha = 0;
94 			break;
95 
96 		default:
97 			revMethod = REVEAL_DEFAULT;
98 			baseMapSegAlpha = 0.4;
99 	}
100 }
101 
102 
103 class WorldMapBoundQuad : public Quad
104 {
105 public:
WorldMapBoundQuad(const Vector & posToUse)106 	WorldMapBoundQuad(const Vector &posToUse)
107 	{
108 		position = posToUse;
109 		truePosition = posToUse;
110 		followCamera = 1;
111 	}
112 
render()113 	void render()
114 	{
115 		setProperPosition();
116 		Quad::render();
117 	}
118 
119 protected:
120 	Vector truePosition;
setProperPosition()121 	void setProperPosition()
122 	{
123 		Vector wp = parent->getWorldCollidePosition(truePosition);
124 		Vector diff = wp - core->center;
125 
126 		float w2 = core->getVirtualWidth()/2;
127 		float h2 = core->getVirtualHeight()/2;
128 
129 		if (diff.x < -w2)
130 			wp.x = core->center.x - w2;
131 		if (diff.x > w2)
132 			wp.x = core->center.x + w2;
133 		if (diff.y < -h2)
134 			wp.y = core->center.y - h2;
135 		if (diff.y > h2)
136 			wp.y = core->center.y + h2;
137 
138 		Vector move = wp - getWorldPosition();
139 		// FIXME: This is a quick HACK to get the current world map
140 		// scale factor so we can set the position properly, without
141 		// having to play with multiple levels of parent pointers or
142 		// anything like that.  (If we don't scale the move vector
143 		// properly, the dots overshoot at high zoom or don't go far
144 		// enough at low zoom and we can end up with a weird "disco"
145 		// effect -- see icculus bug 4542.)
146 		const float x0 = getWorldPosition().x;
147 		position.x += 1;
148 		const float x1 = getWorldPosition().x;
149 		position.x -= 1;
150 		position += move / (x1-x0);
151 	}
152 };
153 
154 class BeaconRender : public Quad
155 {
156 public:
BeaconRender(BeaconData * beaconData)157 	BeaconRender(BeaconData *beaconData) : Quad(), beaconData(beaconData)
158 	{
159 		renderQuad = false;
160 		setTexture("gui/minimap/ripple"); //"particles/softring"); // or whatever
161 		position = beaconData->pos;
162 		truePosition = beaconData->pos;
163 		followCamera = 1;
164 		/*
165 		scale = Vector(0.2, 0.2);
166 		scale.interpolateTo(Vector(0.5, 0.5), 0.75, -1, 1, 1);
167 		*/
168 		alpha = 0.5;
169 		color = beaconData->color;
170 
171 		/*
172 		pe = new ParticleEffect();
173 		pe->load("sparkle");
174 		pe->followCamera = 1;
175 		pe->start();
176 		core->addRenderObject(pe, LR_PARTICLES);
177 		*/
178 		spawnBitTimer = 0;
179 	}
180 
181 	//float spawnBitTimer;
182 	Vector truePosition;
183 
184 	ParticleEffect *pe;
185 
186 	float spawnBitTimer;
187 
188 
render()189 	void render()
190 	{
191 		//setProperPosition();
192 		Quad::render();
193 	}
194 
195 protected:
196 	BeaconData *beaconData;
197 
setProperPosition()198 	void setProperPosition()
199 	{
200 		Vector wp = parent->getWorldCollidePosition(truePosition);
201 		Vector diff = wp - core->center;
202 
203 		float w2 = core->getVirtualWidth()/2;
204 		float h2 = core->getVirtualHeight()/2;
205 
206 		if (diff.x < -w2)
207 			wp.x = core->center.x - w2;
208 		if (diff.x > w2)
209 			wp.x = core->center.x + w2;
210 		if (diff.y < -h2)
211 			wp.y = core->center.y - h2;
212 		if (diff.y > h2)
213 			wp.y = core->center.y + h2;
214 
215 		Vector move = wp - getWorldPosition();
216 		position += move;
217 	}
218 
219 
onUpdate(float dt)220 	void onUpdate(float dt)
221 	{
222 		Quad::onUpdate(dt);
223 
224 		//setProperPosition();
225 
226 		if (!dsq->game->worldMapRender->isOn()) return;
227 
228 		const int lenRange = 125;
229 		const float pscale = 0.7;
230 
231 		float leftOver = dt;
232 
233 		while (leftOver)
234 		{
235 			spawnBitTimer -= leftOver;
236 			if (spawnBitTimer <= 0)
237 			{
238 				leftOver = -spawnBitTimer;
239 				spawnBitTimer = beaconSpawnBitTime;
240 
241 				float r = (rand()%100)/100.0f;
242 				float radius = r * 2*PI;
243 				float len = (rand()%lenRange);
244 				int x = sinf(radius)*len;
245 				int y = cosf(radius)*len;
246 
247 				//truePosition +
248 				float t = 0.75;
249 				WorldMapBoundQuad *q = new WorldMapBoundQuad(Vector(x, y, 0));
250 				q->setTexture("particles/glow");
251 				q->alpha.ensureData();
252 				q->alpha.data->path.addPathNode(0.0, 0.0);
253 				q->alpha.data->path.addPathNode(1.0, 0.5);
254 				q->alpha.data->path.addPathNode(0.0, 1.0);
255 				q->alpha.startPath(0.5);
256 				q->alphaMod = 0.5;
257 				q->color = color;
258 
259 				q->scale = Vector(pscale, pscale);
260 				//q->fadeAlphaWithLife = 1;
261 				q->setLife(1);
262 				q->setDecayRate(1.0f/t);
263 
264 				q->setBlendType(BLEND_ADD);
265 				addChild(q, PM_POINTER);
266 
267 				//std::ostringstream os;
268 				//os << "children: " << children.size();
269 				//debugLog(os.str());
270 			}
271 			else
272 			{
273 				leftOver = 0;
274 			}
275 		}
276 
277 
278 
279 		/*
280 
281 		*/
282 	}
283 
284 };
285 
286 class GemMover : public Quad
287 {
288 public:
GemMover(GemData * gemData)289 	GemMover(GemData *gemData) : Quad(), gemData(gemData)
290 	{
291 		setTexture("Gems/" + gemData->name);
292 		position = gemData->pos;
293 		followCamera = 1;
294 		blink = false;
295 		blinkTimer = 0;
296 		alphaMod = 0.66;
297 		canMove = gemData->canMove;
298 		//canMove = true;
299 		//gemData->userString = "HI THERE!";
300 
301 		std::string useString = gemData->userString;
302 
303 		/*
304 		if (gemData->userString.empty())
305 		{
306 			if (gemData->name == "savepoint")
307 				useString = "Memory Crystal";
308 			if (gemData->name == "cook")
309 				useString = "Kitchen";
310 		}
311 		*/
312 
313 		/*
314 		text = new BitmapText(&dsq->smallFont);
315 		text->position = Vector(0, -20);
316 		text->setText(gemData->userString);
317 		addChild(text, PM_POINTER);
318 		*/
319 
320 		text = new TTFText(&dsq->fontArialSmall);//new DebugFont(10, useString);
321 		text->offset = Vector(0, 4); //Vector(0,5);
322 		text->setText(useString);
323 		text->setAlign(ALIGN_CENTER);
324 
325 		textBG = new RoundedRect();
326 		textBG->setWidthHeight(text->getActualWidth() + 20, 25, 10);  // 30
327 		textBG->alpha = 0;
328 		textBG->followCamera = 1;
329 		game->addRenderObject(textBG, LR_WORLDMAPHUD);
330 
331 		textBG->addChild(text, PM_POINTER);
332 		//game->addRenderObject(text, LR_WORLDMAPHUD);
333 	}
334 
destroy()335 	void destroy()
336 	{
337 		if (textBG)
338 		{
339 			textBG->safeKill();
340 			textBG = 0;
341 		}
342 		Quad::destroy();
343 	}
344 
getGemData()345 	GemData *getGemData() { return gemData; }
346 
setBlink(bool blink)347 	void setBlink(bool blink)
348 	{
349 		this->blink = blink;
350 
351 		//if (blink)
352 		//{
353 		//	scale = Vector(0.5, 0.5);
354 		//	scale.interpolateTo(Vector(1,1), 0.5, -1, 1);
355 		//	/*
356 		//	alpha = 0.5;
357 		//	alpha.interpolateTo(1, 0.5, -1, 1);
358 		//	*/
359 		//}
360 		//else
361 		//{
362 		//	scale.stop();
363 		//	scale = Vector(1,1);
364 		//	/*
365 		//	alpha.stop();
366 		//	alpha = 1;
367 		//	*/
368 		//}
369 	}
370 	bool canMove;
371 protected:
372 
373 	float blinkTimer;
374 	bool blink;
375 	GemData *gemData;
376 	//BitmapText *text;
377 	TTFText *text;
378 	RoundedRect *textBG;
onUpdate(float dt)379 	void onUpdate(float dt)
380 	{
381 		Quad::onUpdate(dt);
382 
383 		Vector sz = parent->scale;
384 
385 		if (sz.x < zoomMin)
386 			sz.x = sz.y = zoomMin;
387 		if (sz.x > zoomMax)
388 			sz.x = sz.y = zoomMax;
389 
390 		if (sz.x > 1.0f)
391 		{
392 			scale.x = (1.0f/sz.x);
393 			scale.y = (1.0f/sz.y);
394 		}
395 		else
396 		{
397 			scale = Vector(1,1);
398 		}
399 
400 		Vector wp = getWorldPosition();
401 
402 		if (blink)
403 		{
404 			blinkTimer += dt;
405 			if (blinkTimer > blinkPeriod)
406 			{
407 				if (alphaMod == 0)
408 					alphaMod = 1;
409 				else
410 					alphaMod = 0;
411 
412 				blinkTimer = 0;
413 			}
414 		}
415 
416 		if (canMove)
417 		{
418 			if (mover == 0)
419 			{
420 				if (core->mouse.buttons.left && (core->mouse.position - wp).isLength2DIn(GEM_GRAB))
421 				{
422 					core->sound->playSfx("Gem-Move");
423 					mover = this;
424 					//offset = Vector(position - core->mouse.position);
425 					//position += core->mouse.position - wp;
426 					//offset = Vector(0, 4);
427 				}
428 			}
429 			else if (mover == this)
430 			{
431 				//position = core->mouse.position;
432 				position += (core->mouse.position - wp)/parent->scale.x;
433 				if (!core->mouse.buttons.left)
434 				{
435 					mover = 0;
436 					core->sound->playSfx("Gem-Place");
437 					//position += offset;
438 					//offset = Vector(0,0);
439 					//offset = Vector(0,0);
440 					gemData->pos = position;
441 				}
442 			}
443 		}
444 
445 
446 		if (textBG)
447 		{
448 			textBG->position = getWorldPosition() + Vector(0, -20);
449 		}
450 
451 		if ((core->mouse.position - wp).isLength2DIn(GEM_GRAB))
452 		{
453 			//text->alpha.interpolateTo(1, 0.1);
454 			/*
455 			if (!gemData->userString.empty())
456 			textBG->alpha.interpolateTo(1, 0.1);
457 			*/
458 			if (!gemData->userString.empty())
459 				textBG->show();
460 		}
461 		else
462 		{
463 			/*
464 			text->alpha.interpolateTo(0, 0.1);
465 			textBG->alpha.interpolateTo(0, 0.1);
466 			*/
467 			if (textBG->alpha == 1)
468 				textBG->hide();
469 		}
470 	}
471 };
472 
473 typedef std::list <GemMover*> GemMovers;
474 GemMovers gemMovers;
475 
476 typedef std::list <BeaconRender*> BeaconRenders;
477 BeaconRenders beaconRenders;
478 
479 std::vector<Quad*> quads;
480 
setProperTileColor(WorldMapTile * tile)481 void WorldMapRender::setProperTileColor(WorldMapTile *tile)
482 {
483 	if (tile)
484 	{
485 		if (tile->q)
486 		{
487 			if (!tile->revealed)
488 				tile->q->alphaMod = 0;
489 
490 			if (tile->revealed)
491 				tile->q->alphaMod = 0.5;
492 
493 			if (activeTile && (tile->layer != activeTile->layer || (tile->layer > 0 && activeTile != tile)))
494 				tile->q->alphaMod *= 0.5;
495 
496 			tile->q->color = Vector(0.7, 0.8, 1);
497 		}
498 		else
499 		{
500 			debugLog("no Q!");
501 		}
502 	}
503 }
504 
505 #ifdef AQUARIA_BUILD_MAPVIS
506 
tileDataToVis(WorldMapTile * tile,Vector ** vis)507 static void tileDataToVis(WorldMapTile *tile, Vector **vis)
508 {
509 	const unsigned char *data = tile->getData();
510 
511 	if (data != 0)
512 	{
513 		const float a = tile->prerevealed ? 0.4f :  baseMapSegAlpha;
514 		const unsigned int rowSize = MAPVIS_SUBDIV/8;
515 		for (unsigned int y = 0; y < MAPVIS_SUBDIV; y++, data += rowSize)
516 		{
517 			for (unsigned int x = 0; x < MAPVIS_SUBDIV; x += 8)
518 			{
519 				unsigned char dataByte = data[x/8];
520 				for (unsigned int x2 = 0; x2 < 8; x2++)
521 				{
522 					vis[x+x2][y].z = (dataByte & (1 << x2)) ? visibleMapSegAlpha : a;
523 				}
524 			}
525 		}
526 	}
527 	else
528 	{
529 		const float a = tile->prerevealed ? 0.4f :  baseMapSegAlpha;
530 		for (int x = 0; x < MAPVIS_SUBDIV; x++)
531 		{
532 			for (int y = 0; y < MAPVIS_SUBDIV; y++)
533 			{
534 				vis[x][y].z = a;
535 			}
536 		}
537 		return;
538 	}
539 }
540 
541 // Returns a copy of the original texture data.
tileDataToAlpha(WorldMapTile * tile)542 static unsigned char *tileDataToAlpha(WorldMapTile *tile)
543 {
544 	const unsigned char *data = tile->getData();
545 	const unsigned int ab = int(baseMapSegAlpha * (1<<8) + 0.5f);
546 	const unsigned int av = int(visibleMapSegAlpha * (1<<8) + 0.5f);
547 
548 	const unsigned int texWidth = tile->q->texture->width;
549 	const unsigned int texHeight = tile->q->texture->height;
550 	if (texWidth % MAPVIS_SUBDIV != 0 || texHeight % MAPVIS_SUBDIV != 0)
551 	{
552 		std::ostringstream os;
553 		os << "Texture size " << texWidth << "x" << texHeight
554 		   << " not a multiple of MAPVIS_SUBDIV " << MAPVIS_SUBDIV
555 		   << ", can't edit";
556 		debugLog(os.str());
557 		return 0;
558 	}
559 	const unsigned int scaleX = texWidth / MAPVIS_SUBDIV;
560 	const unsigned int scaleY = texHeight / MAPVIS_SUBDIV;
561 
562 	unsigned char *savedTexData = new unsigned char[texWidth * texHeight * 4];
563 	tile->q->texture->read(0, 0, texWidth, texHeight, savedTexData);
564 
565 	unsigned char *texData = new unsigned char[texWidth * texHeight * 4];
566 	memcpy(texData, savedTexData, texWidth * texHeight * 4);
567 
568 	if (data != 0)
569 	{
570 		const unsigned int rowSize = MAPVIS_SUBDIV/8;
571 		for (unsigned int y = 0; y < MAPVIS_SUBDIV; y++, data += rowSize)
572 		{
573 			unsigned char *texOut = &texData[(y*scaleY) * texWidth * 4];
574 			for (unsigned int x = 0; x < MAPVIS_SUBDIV; x += 8)
575 			{
576 				unsigned char dataByte = data[x/8];
577 				for (unsigned int x2 = 0; x2 < 8; x2++, texOut += scaleX*4)
578 				{
579 					const bool visited = (dataByte & (1 << x2)) != 0;
580 					const unsigned int alphaMod = visited ? av : ab;
581 					for (unsigned int pixelY = 0; pixelY < scaleY; pixelY++)
582 					{
583 						unsigned char *ptr = &texOut[pixelY * texWidth * 4];
584 						for (unsigned int pixelX = 0; pixelX < scaleX; pixelX++, ptr += 4)
585 						{
586 							if (ptr[3] == 0)
587 								continue;
588 							ptr[3] = (ptr[3] * alphaMod + 128) >> 8;
589 						}
590 					}
591 				}
592 			}
593 		}
594 	}
595 	else
596 	{
597 		unsigned char *texOut = texData;
598 		for (unsigned int y = 0; y < texHeight; y++)
599 		{
600 			for (unsigned int x = 0; x < texWidth; x++, texOut += 4)
601 			{
602 				texOut[3] = (texOut[3] * ab + 128) >> 8;
603 			}
604 		}
605 	}
606 
607 	tile->q->texture->write(0, 0, texWidth, texHeight, texData);
608 	delete[] texData;
609 
610 	return savedTexData;
611 }
612 
resetTileAlpha(WorldMapTile * tile,const unsigned char * savedTexData)613 static void resetTileAlpha(WorldMapTile *tile, const unsigned char *savedTexData)
614 {
615 	tile->q->texture->write(0, 0, tile->q->texture->width, tile->q->texture->height, savedTexData);
616 }
617 
618 #endif  // AQUARIA_BUILD_MAPVIS
619 
620 
setVis(WorldMapTile * tile)621 void WorldMapRender::setVis(WorldMapTile *tile)
622 {
623 	if (!tile) return;
624 #ifdef AQUARIA_BUILD_MAPVIS
625 	/*
626 	if (lastVisQuad)
627 	{
628 		lastVisQuad->alphaMod = 0.5;
629 		lastVisQuad->color = Vector(0.7, 0.8, 1);
630 	}
631 	*/
632 
633 	tile->q->color = Vector(1,1,1);
634 	tile->q->alphaMod = 1;
635 
636 	if (visMethod == VIS_VERTEX)
637 	{
638 		tile->q->setSegs(MAPVIS_SUBDIV, MAPVIS_SUBDIV, 0, 0, 0, 0, 2.0, 1);
639 		tileDataToVis(tile, tile->q->getDrawGrid());
640 	}
641 	else if (visMethod == VIS_WRITE)
642 	{
643 		savedTexData = tileDataToAlpha(tile);
644 	}
645 
646 	lastVisQuad = tile->q;
647 	lastVisTile = tile;
648 #endif
649 }
650 
clearVis(WorldMapTile * tile)651 void WorldMapRender::clearVis(WorldMapTile *tile)
652 {
653 	if (!tile) return;
654 #ifdef AQUARIA_BUILD_MAPVIS
655 	if (visMethod == VIS_VERTEX)
656 	{
657 		if (tile->q)
658 			tile->q->deleteGrid();
659 	}
660 	else if (visMethod == VIS_WRITE)
661 	{
662 		if (savedTexData)
663 		{
664 			resetTileAlpha(tile, savedTexData);
665 			delete[] savedTexData;
666 			savedTexData = 0;
667 		}
668 	}
669 #endif
670 }
671 
672 
WorldMapRender()673 WorldMapRender::WorldMapRender() : RenderObject(), ActionMapper()
674 {
675 	doubleClickTimer = 0;
676 	inputDelay = 0;
677 	editorActive=false;
678 	mb = false;
679 	activeQuad=0;
680 	lastActiveQuad=0;
681 	originalActiveQuad=0;
682 	lastVisQuad=0;
683 	visQuad=0;
684 	lastVisTile=0;
685 
686 	originalActiveTile = activeTile = 0;
687 
688 	areaLabel = 0;
689 
690 	on = false;
691 	alpha = 0;
692 
693 	scale = Vector(1, 1);
694 	followCamera = 1;
695 	cull = false;
696 	position = Vector(400,300);
697 
698 	activeTile = 0;
699 	activeQuad = 0;
700 
701 	lastMousePosition = core->mouse.position;
702 
703 	bg = 0;
704 
705 	savedTexData = 0;
706 
707 	/*
708 	bg = new Quad("", Vector(400,300));
709 	bg->setWidthHeight(810, 610);
710 	bg->setSegs(32, 32, 0.5, 0.5, 0.008, 0.008, 2.0, 1);
711 	bg->alphaMod = 0.5;
712 	bg->alpha = 0;
713 	bg->followCamera = 1;
714 	bg->repeatTextureToFill(true);
715 	//bg->parentManagedPointer = 1;
716 	dsq->game->addRenderObject(bg, LR_MESSAGEBOX);
717 
718 	bg->renderQuad = false;
719 	*/
720 
721 	int num = dsq->continuity.worldMap.getNumWorldMapTiles();
722 	std::string n = dsq->game->sceneName;
723 	stringToUpper(n);
724 	for (int i = 0; i < num; i++)
725 	{
726 		WorldMapTile *tile = dsq->continuity.worldMap.getWorldMapTile(i);
727 		if (tile)
728 		{
729 			if (tile->name == n)
730 			{
731 				activeTile = tile;
732 				break;
733 			}
734 		}
735 	}
736 
737 	tiles.clear();
738 
739 	for (int i = 0; i < num; i++)
740 	{
741 		WorldMapTile *tile = dsq->continuity.worldMap.getWorldMapTile(i);
742 		if (tile)
743 		{
744 			Vector pos(tile->gridPos.x, tile->gridPos.y);
745 
746 			Quad *q = new Quad;
747 			std::string tn = "Gui/WorldMap/" + tile->name;
748 			q->setTexture(tn);
749 			q->position = pos;
750 			q->alphaMod = 0;
751 
752 			tile->q = q;
753 
754 			q->setWidthHeight(q->getWidth()*tile->scale, q->getHeight()*tile->scale);
755 			q->scale = Vector(0.25f*tile->scale2, 0.25f*tile->scale2);
756 
757 			if (tile == activeTile)
758 				activeQuad = q;
759 
760 			if (revMethod == REVEAL_PARTIAL || activeQuad == q)
761 			{
762 				setVis(tile);
763 			}
764 
765 			setProperTileColor(tile);
766 
767 			if(activeQuad == q)
768 			{
769 				activeTile->q->color = Vector(1,1,1);
770 				activeTile->q->alphaMod = 1;
771 			}
772 
773 			addChild(q, PM_POINTER);
774 
775 			tiles.push_back(q);
776 		}
777 	}
778 	shareAlphaWithChildren = 1;
779 
780 	dsq->user.control.actionSet.importAction(this, "SwimLeft",	ACTION_SWIMLEFT);
781 	dsq->user.control.actionSet.importAction(this, "SwimRight", ACTION_SWIMRIGHT);
782 	dsq->user.control.actionSet.importAction(this, "SwimUp",	ACTION_SWIMUP);
783 	dsq->user.control.actionSet.importAction(this, "SwimDown",	ACTION_SWIMDOWN);
784 
785 	// where old scale + position set were
786 
787 	tophud = new Quad("gui/worldmap-ui", Vector(400,64));
788 	tophud->followCamera = 1;
789 	tophud->alpha = 0;
790 	dsq->game->addRenderObject(tophud, LR_WORLDMAPHUD);
791 
792 	//int fontSize = 6;
793 	float aly = 26, aly2 = 18;
794 	float sz = 0.6;
795 
796 	//hover
797 	areaLabel = new BitmapText(&dsq->smallFont);
798 	areaLabel->scale = Vector(sz,sz);
799 	//areaLabel->setFontSize(fontSize);
800 	areaLabel->setAlign(ALIGN_CENTER);
801 	areaLabel->followCamera = 1;
802 	areaLabel->position = Vector(150,aly);
803 	dsq->game->addRenderObject(areaLabel, LR_WORLDMAPHUD);
804 	areaLabel->alpha = 0;
805 
806 	//in
807 	areaLabel2 = new BitmapText(&dsq->smallFont);
808 	//areaLabel2->setFontSize(fontSize);
809 	areaLabel2->scale = Vector(sz,sz);
810 	areaLabel2->followCamera = 1;
811 	areaLabel2->setAlign(ALIGN_CENTER);
812 	areaLabel2->position = Vector(400,aly2);
813 	dsq->game->addRenderObject(areaLabel2, LR_WORLDMAPHUD);
814 	areaLabel2->alpha = 0;
815 
816 	//select
817 	areaLabel3 = new BitmapText(&dsq->smallFont);
818 	areaLabel3->scale = Vector(sz,sz);
819 	//areaLabel3->setFontSize(fontSize);
820 	areaLabel3->followCamera = 1;
821 	areaLabel3->setAlign(ALIGN_CENTER);
822 	areaLabel3->position = Vector(650, aly);
823 	areaLabel3->alpha = 0;
824 	dsq->game->addRenderObject(areaLabel3, LR_WORLDMAPHUD);
825 
826 	if (activeTile)
827 	{
828 		areaLabel2->setText(dsq->continuity.stringBank.get(activeTile->stringIndex));
829 	}
830 
831 	originalActiveTile = activeTile;
832 
833 	bindInput();
834 
835 	underlay = new Gradient;
836 	//underlay->makeVertical(Vector(0.5,0.5,1), Vector(0,0,0.5));
837 	underlay->makeVertical(Vector(0.25,0.25,0.5), Vector(0,0,0.25));
838 	underlay->position = Vector(400,300);
839 	underlay->autoWidth = AUTO_VIRTUALWIDTH;
840 	underlay->autoHeight = AUTO_VIRTUALHEIGHT;
841 	underlay->followCamera = 1;
842 	underlay->alpha = 0;
843 	dsq->game->addRenderObject(underlay, LR_HUDUNDERLAY);
844 
845 	addHintQuad1 = new Quad("gems/pyramidyellow", Vector(0,0));
846 	addHintQuad1->followCamera = 1;
847 	addHintQuad1->alpha = 0;
848 	dsq->game->addRenderObject(addHintQuad1, LR_WORLDMAPHUD);
849 
850 	addHintQuad2 = new Quad("gems/pyramidpurple", Vector(0,0));
851 	addHintQuad2->followCamera = 1;
852 	addHintQuad2->alpha = 0;
853 	dsq->game->addRenderObject(addHintQuad2, LR_WORLDMAPHUD);
854 
855 	//helpButton->event.set(MakeFunctionEvent(WorldMapRender, onToggleHelpScreen));
856 	helpButton = new AquariaMenuItem;
857 	helpButton->event.setActionMapperCallback(this, ACTION_TOGGLEHELPSCREEN, 0);
858 	helpButton->useQuad("gui/icon-help");
859 	helpButton->useGlow("particles/glow", 40, 40);
860 	helpButton->useSound("Click");
861 	helpButton->alpha = 0;
862 	//helpButton->position = Vector(800-20, 20);
863 	dsq->game->addRenderObject(helpButton, LR_WORLDMAPHUD);
864 }
865 
onToggleHelpScreen()866 void WorldMapRender::onToggleHelpScreen()
867 {
868 	game->toggleHelpScreen();
869 }
870 
bindInput()871 void WorldMapRender::bindInput()
872 {
873 	clearActions();
874 	clearCreatedEvents();
875 
876 	addAction(ACTION_TOGGLEWORLDMAPEDITOR, KEY_TAB);
877 
878 	dsq->user.control.actionSet.importAction(this, "PrimaryAction",		ACTION_PRIMARY);
879 	dsq->user.control.actionSet.importAction(this, "SecondaryAction",	ACTION_SECONDARY);
880 
881 	dsq->user.control.actionSet.importAction(this, "SwimLeft",			ACTION_SWIMLEFT);
882 	dsq->user.control.actionSet.importAction(this, "SwimRight",			ACTION_SWIMRIGHT);
883 	dsq->user.control.actionSet.importAction(this, "SwimUp",			ACTION_SWIMUP);
884 	dsq->user.control.actionSet.importAction(this, "SwimDown",			ACTION_SWIMDOWN);
885 }
886 
destroy()887 void WorldMapRender::destroy()
888 {
889 	//clearVis(activeTile);
890 	for (int i = 0; i < dsq->continuity.worldMap.getNumWorldMapTiles(); i++)
891 	{
892 		WorldMapTile *tile = dsq->continuity.worldMap.getWorldMapTile(i);
893 		clearVis(tile);
894 	}
895 
896 	RenderObject::destroy();
897 	delete[] savedTexData;
898 }
899 
isCursorOffHud()900 bool WorldMapRender::isCursorOffHud()
901 {
902 	if (helpButton && helpButton->isCursorInMenuItem())
903 	{
904 		return false;
905 	}
906 	return true;
907 }
908 
onUpdate(float dt)909 void WorldMapRender::onUpdate(float dt)
910 {
911 	if (AquariaGuiElement::currentGuiInputLevel > 0) return;
912 
913 	RenderObject::onUpdate(dt);
914 	ActionMapper::onUpdate(dt);
915 
916 	if (areaLabel)
917 		areaLabel->alpha.x = this->alpha.x;
918 
919 	if (areaLabel2)
920 		areaLabel2->alpha.x = this->alpha.x;
921 
922 	if (areaLabel3)
923 		areaLabel3->alpha.x = this->alpha.x;
924 
925 	if (tophud)
926 		tophud->alpha.x = this->alpha.x;
927 
928 	const float mmWidth  = game->miniMapRender->getMiniMapWidth();
929 	const float mmHeight = game->miniMapRender->getMiniMapHeight();
930 	if (addHintQuad1)
931 		addHintQuad1->position = game->miniMapRender->position + Vector(-mmWidth*3/22, -mmHeight/2-10);
932 
933 	if (addHintQuad2)
934 		addHintQuad2->position = game->miniMapRender->position + Vector(mmWidth*3/22, -mmHeight/2-10);
935 
936 	int offset = 26;
937 	if (helpButton)
938 		helpButton->position = Vector(core->getVirtualWidth()-core->getVirtualOffX()-offset, offset);
939 
940 	if (alpha.x > 0)
941 	{
942 		//if (activeTile && activeTile==originalActiveTile && !gemMovers.empty())
943 		if (originalActiveTile && !gemMovers.empty())
944 		{
945 			gemMovers.back()->position = getAvatarWorldMapPosition();
946 		}
947 	}
948 
949 	if (doubleClickTimer > 0)
950 	{
951 		doubleClickTimer -= dt;
952 		if (doubleClickTimer < 0)
953 			doubleClickTimer = 0;
954 	}
955 
956 	if (isOn())
957 	{
958 		if (inputDelay > 0)
959 		{
960 			inputDelay -= dt;
961 			if (inputDelay < 0) inputDelay = 0;
962 		}
963 		else
964 		{
965 			WorldMapTile *selectedTile = 0;
966 			int sd=-1,d=0;
967 			for (int i = 0; i < dsq->continuity.worldMap.getNumWorldMapTiles(); i++)
968 			{
969 				WorldMapTile *tile = dsq->continuity.worldMap.getWorldMapTile(i);
970 				if (tile && tile != activeTile)
971 				{
972 					if (tile->revealed || tile->prerevealed)
973 					{
974 						Quad *q = tile->q;
975 						if (q)
976 						{
977 							d = (q->getWorldPosition() - core->mouse.position).getSquaredLength2D();
978 
979 							if (q->isCoordinateInsideWorld(core->mouse.position) && (sd == -1 || d < sd))
980 							{
981 								sd = d;
982 								selectedTile = tile;
983 								break;
984 							}
985 						}
986 					}
987 				}
988 			}
989 
990 			if (!editorActive)
991 			{
992 				if (activeTile)
993 				{
994 					areaLabel3->setText(dsq->continuity.stringBank.get(activeTile->stringIndex));
995 				}
996 
997 				if (selectedTile)
998 				{
999 					areaLabel->setText(dsq->continuity.stringBank.get(selectedTile->stringIndex));
1000 
1001 					if (activeTile && !mover && !dsq->isNested() && isCursorOffHud())
1002 					{
1003 						if (!core->mouse.buttons.left && mb)
1004 						{
1005 							if ((activeTile != selectedTile) && selectedTile->q)
1006 							{
1007 								if(revMethod == REVEAL_DEFAULT)
1008 									clearVis(activeTile);
1009 
1010 								activeTile = selectedTile;
1011 								activeQuad = activeTile->q;
1012 								//activeTile->gridPos = activeTile->q->position;
1013 								if (activeQuad)
1014 								{
1015 									dsq->clickRingEffect(activeQuad->getWorldPosition(), 0);
1016 
1017 									dsq->sound->playSfx("bubble-lid");
1018 									dsq->sound->playSfx("menuselect");
1019 								}
1020 
1021 								int num = dsq->continuity.worldMap.getNumWorldMapTiles();
1022 								for (int i = 0; i < num; i++)
1023 								{
1024 									WorldMapTile *tile = dsq->continuity.worldMap.getWorldMapTile(i);
1025 									setProperTileColor(tile);
1026 								}
1027 
1028 								setVis(selectedTile);
1029 							}
1030 
1031 							mb = false;
1032 						}
1033 						else if (core->mouse.buttons.left && !mb)
1034 						{
1035 							mb = true;
1036 						}
1037 					}
1038 					else
1039 					{
1040 						mb = false;
1041 					}
1042 				}
1043 				else
1044 				{
1045 					areaLabel->setText("");
1046 				}
1047 			}
1048 		}
1049 
1050 		if (!core->mouse.buttons.left && mb)
1051 			mb = false;
1052 
1053 		if (core->mouse.buttons.middle || core->mouse.buttons.right)
1054 		{
1055 			// FIXME: For some reason, not all mouse movement events reach
1056 			// this handler (at least under Linux/SDL), so when moving the
1057 			// mouse quickly, the world map scrolling tends to lag behind.
1058 			// We work around this by keeping our own "last position" vector
1059 			// and calculating the mouse movement from that.  --achurch
1060 			Vector mouseChange = core->mouse.position - lastMousePosition;
1061 			internalOffset += mouseChange / scale.x;
1062 		}
1063 
1064 		if(!editorActive)
1065 		{
1066 			float scrollSpeed = 2.0f;
1067 			float amt = (400*dt)/scale.x;
1068 			if (isActing(ACTION_SWIMLEFT))
1069 			{
1070 				internalOffset += Vector(amt, 0);
1071 			}
1072 			if (isActing(ACTION_SWIMRIGHT))
1073 			{
1074 				internalOffset += Vector(-amt, 0);
1075 			}
1076 			if (isActing(ACTION_SWIMDOWN))
1077 			{
1078 				if (core->getShiftState())
1079 				{
1080 					scale.stop();
1081 					scale -= Vector(scrollSpeed*dt, scrollSpeed*dt);
1082 				}
1083 				else
1084 				{
1085 					internalOffset += Vector(0, -amt);
1086 				}
1087 			}
1088 			if (isActing(ACTION_SWIMUP))
1089 			{
1090 				if (core->getShiftState())
1091 				{
1092 					scale.stop();
1093 					scale += Vector(scrollSpeed*dt, scrollSpeed*dt);
1094 				}
1095 				else
1096 				{
1097 					internalOffset += Vector(0, amt);
1098 				}
1099 			}
1100 
1101 			if (core->joystickEnabled)
1102 			{
1103 				if (isActing(ACTION_SECONDARY))
1104 				{
1105 					if (core->joystick.position.y >= 0.6f)
1106 						scale.interpolateTo(scale / 1.2f, 0.1f);
1107 					else if (core->joystick.position.y <= -0.6f)
1108 						scale.interpolateTo(scale * 1.2f, 0.1f);
1109 				}
1110 				else
1111 				{
1112 					// The negative multiplier is deliberate -- it makes the
1113 					// map scroll as though the joystick was controlling the
1114 					// cursor (which is fixed in the center of the screen).
1115 					internalOffset += core->joystick.position * (-400*dt / scale.x);
1116 				}
1117 			}
1118 		}
1119 
1120 		if (activeTile && activeTile->layer == 1)
1121 		{
1122 			zoomMax = interiorZoomMax;
1123 		}
1124 		else
1125 		{
1126 			zoomMax = exteriorZoomMax;
1127 		}
1128 
1129 		float scrollAmount = 0.2;//0.25;
1130 
1131 		if (core->mouse.scrollWheelChange)
1132 		{
1133 			Vector target = scale;
1134 			int changeLeft = core->mouse.scrollWheelChange;
1135 			for (; changeLeft > 0; changeLeft--)
1136 				target *= 1 + scrollAmount;
1137 			for (; changeLeft < 0; changeLeft++)
1138 				target /= 1 + scrollAmount;
1139 			scale.interpolateTo(target, 0.1);
1140 		}
1141 
1142 		if (scale.x < zoomMin)
1143 		{
1144 			scale.stop();
1145 			scale.x = scale.y = zoomMin;
1146 		}
1147 		if (scale.x > zoomMax)
1148 		{
1149 			scale.stop();
1150 			scale.x = scale.y = zoomMax;
1151 		}
1152 
1153 		if (-internalOffset.x < xMin - 300/scale.x)
1154 			internalOffset.x = -(xMin - 300/scale.x);
1155 		else if (-internalOffset.x > xMax + 300/scale.x)
1156 			internalOffset.x = -(xMax + 300/scale.x);
1157 		if (-internalOffset.y < yMin - 225/scale.x)
1158 			internalOffset.y = -(yMin - 225/scale.x);
1159 		else if (-internalOffset.y > yMax + 150/scale.x)
1160 			internalOffset.y = -(yMax + 150/scale.x);
1161 
1162 		if (dsq->canOpenEditor())
1163 		{
1164 			if (editorActive)
1165 			{
1166 				if (activeTile && activeQuad)
1167 				{
1168 					float amt = dt*4;
1169 					float a2 = dt*0.1f;
1170 
1171 					if (core->getShiftState())
1172 					{
1173 						if (core->getCtrlState())
1174 							a2 *= 10.0f;
1175 						if (core->getKeyState(KEY_UP))
1176 							activeTile->scale2 += -a2;
1177 						if (core->getKeyState(KEY_DOWN))
1178 							activeTile->scale2 += a2;
1179 					}
1180 					else if (core->getAltState())
1181 					{
1182 						if (core->getCtrlState())
1183 							a2 *= 10.0f;
1184 						if (core->getKeyState(KEY_UP))
1185 							activeTile->scale += -a2;
1186 						if (core->getKeyState(KEY_DOWN))
1187 							activeTile->scale += a2;
1188 					}
1189 					else
1190 					{
1191 						if (core->getCtrlState())
1192 						{
1193 							amt *= 50;
1194 						}
1195 						if (core->getKeyState(KEY_LEFT))
1196 							activeTile->gridPos += Vector(-amt, 0);
1197 						if (core->getKeyState(KEY_RIGHT))
1198 							activeTile->gridPos += Vector(amt, 0);
1199 						if (core->getKeyState(KEY_UP))
1200 							activeTile->gridPos += Vector(0, -amt);
1201 						if (core->getKeyState(KEY_DOWN))
1202 							activeTile->gridPos += Vector(0, amt);
1203 					}
1204 
1205 					if (core->getKeyState(KEY_F2))
1206 					{
1207 						dsq->continuity.worldMap.save();
1208 					}
1209 
1210 					activeQuad->position = activeTile->gridPos;
1211 					activeQuad->scale = Vector(0.25f*activeTile->scale2, 0.25f*activeTile->scale2);
1212 					if(activeQuad->texture)
1213 						activeQuad->setWidthHeight(activeQuad->texture->width*activeTile->scale, // FG: HACK force resize proper
1214 												   activeQuad->texture->height*activeTile->scale);
1215 				}
1216 				updateEditor();
1217 			}
1218 		}
1219 	}
1220 	else
1221 	{
1222 #ifdef AQUARIA_BUILD_MAPVIS
1223 		if (!dsq->isInCutscene() && dsq->game->avatar && activeTile
1224 	#ifdef AQUARIA_BUILD_SCENEEDITOR
1225 			&& !dsq->game->sceneEditor.isOn()
1226 	#endif
1227 			)
1228 		{
1229 			const float screenWidth  = core->getVirtualWidth()  * core->invGlobalScale;
1230 			const float screenHeight = core->getVirtualHeight() * core->invGlobalScale;
1231 			Vector camera = core->cameraPos;
1232 			camera.x += screenWidth/2;
1233 			camera.y += screenHeight/2;
1234 			const float visWidth  = screenWidth  * visitedFraction;
1235 			const float visHeight = screenHeight * visitedFraction;
1236 			Vector tl, br;
1237 			tl.x = (camera.x - visWidth/2 ) / dsq->game->cameraMax.x;
1238 			tl.y = (camera.y - visHeight/2) / dsq->game->cameraMax.y;
1239 			br.x = (camera.x + visWidth/2 ) / dsq->game->cameraMax.x;
1240 			br.y = (camera.y + visHeight/2) / dsq->game->cameraMax.y;
1241 			const int x0 = int(tl.x * MAPVIS_SUBDIV);
1242 			const int y0 = int(tl.y * MAPVIS_SUBDIV);
1243 			const int x1 = int(br.x * MAPVIS_SUBDIV);
1244 			const int y1 = int(br.y * MAPVIS_SUBDIV);
1245 			activeTile->markVisited(x0, y0, x1, y1);
1246 			if (activeQuad)
1247 			{
1248 				if (visMethod == VIS_VERTEX)
1249 				{
1250 					for (int x = x0; x <= x1; x++)
1251 					{
1252 						for (int y = y0; y <= y1; y++)
1253 						{
1254 							activeQuad->setDrawGridAlpha(x, y, visibleMapSegAlpha);
1255 						}
1256 					}
1257 				}
1258 				else if (visMethod == VIS_WRITE)
1259 				{
1260 					// Do nothing -- we regenerate the tile on opening the map.
1261 				}
1262 			}
1263 		}
1264 #endif
1265 	}
1266 
1267 	lastMousePosition = core->mouse.position;
1268 }
1269 
getAvatarWorldMapPosition()1270 Vector WorldMapRender::getAvatarWorldMapPosition()
1271 {
1272 	Vector p;
1273 	if (originalActiveTile && dsq->game && dsq->game->avatar)
1274 	{
1275 		Vector p = dsq->game->avatar->position;
1276 		if (!dsq->game->avatar->warpInLocal.isZero())
1277 		{
1278 			p = dsq->game->avatar->warpInLocal;
1279 		}
1280 		return getWorldToTile(originalActiveTile, p, true, true);
1281 	}
1282 	return p;
1283 }
1284 
getWorldToTile(WorldMapTile * tile,Vector position,bool fromCenter,bool tilePos)1285 Vector WorldMapRender::getWorldToTile(WorldMapTile *tile, Vector position, bool fromCenter, bool tilePos)
1286 {
1287 	const float sizew = (float)tile->q->texture->width;
1288 	const float halfw = sizew / 2.0f;
1289 	const float sizeh = (float)tile->q->texture->height;
1290 	const float halfh = sizeh / 2.0f;
1291 	Vector p;
1292 	p = Vector((position.x/TILE_SIZE) / (sizew*tile->scale), (position.y/TILE_SIZE) / (sizeh*tile->scale));
1293 	p.x *= sizew*tile->scale*0.25f*tile->scale2;
1294 	p.y *= sizeh*tile->scale*0.25f*tile->scale2;
1295 	if (fromCenter)
1296 		p -= Vector((halfw*tile->scale)*(0.25f*tile->scale2), (halfh*tile->scale)*(0.25f*tile->scale2));
1297 	if (tilePos)
1298 		p += tile->gridPos;
1299 	return p;
1300 }
1301 
onRender()1302 void WorldMapRender::onRender()
1303 {
1304 	RenderObject::onRender();
1305 }
1306 
isOn()1307 bool WorldMapRender::isOn()
1308 {
1309 	return this->on;
1310 }
1311 
addGem(GemData * gemData)1312 GemMover *WorldMapRender::addGem(GemData *gemData)
1313 {
1314 	GemMover *g = new GemMover(gemData);
1315 	addChild(g, PM_POINTER);
1316 	gemMovers.push_back(g);
1317 	g->update(0);
1318 	return g;
1319 }
1320 
removeGem(GemMover * gem)1321 void WorldMapRender::removeGem(GemMover *gem)
1322 {
1323 	dsq->continuity.removeGemData(gem->getGemData());
1324 	fixGems();
1325 }
1326 
fixGems()1327 void WorldMapRender::fixGems()
1328 {
1329 	for (GemMovers::iterator i = gemMovers.begin(); i != gemMovers.end(); i++)
1330 	{
1331 		removeChild(*i);
1332 		(*i)->destroy();
1333 		delete *i;
1334 	}
1335 	gemMovers.clear();
1336 	addAllGems();
1337 }
1338 
addAllGems()1339 void WorldMapRender::addAllGems()
1340 {
1341 	int c = 0;
1342 	for (Continuity::Gems::reverse_iterator i = dsq->continuity.gems.rbegin(); i != dsq->continuity.gems.rend(); i++)
1343 	{
1344 		GemMover *g = addGem(&(*i));
1345 		if (c == dsq->continuity.gems.size()-1 || i->blink)
1346 			g->setBlink(true);
1347 		else
1348 			g->setBlink(false);
1349 		c++;
1350 	}
1351 }
1352 
toggle(bool turnON)1353 void WorldMapRender::toggle(bool turnON)
1354 {
1355 	if (AquariaGuiElement::currentGuiInputLevel > 0) return;
1356 	if (dsq->game->miniMapRender->isRadarHide()) return;
1357 	if (alpha.isInterpolating()) return;
1358 
1359 	if (dsq->mod.isActive() && !dsq->mod.hasWorldMap()) return;
1360 
1361 	if (dsq->isNested()) return;
1362 
1363 	if (!dsq->game->avatar) return;
1364 
1365 	if (turnON && dsq->game->avatar->isSinging()) return;
1366 
1367 	if (dsq->game->isInGameMenu()) return;
1368 
1369 	if (!dsq->game->isActive()) return;
1370 
1371 	if (turnON && dsq->game->isPaused()) return;
1372 
1373 	if (!this->on && !dsq->game->avatar->isInputEnabled()) return;
1374 
1375 	const SeeMapMode mapmode = dsq->game->avatar->getSeeMapMode();
1376 
1377 	if (mapmode == SEE_MAP_NEVER
1378 		|| (mapmode == SEE_MAP_DEFAULT && dsq->game->avatar->isInDarkness() && dsq->continuity.form != FORM_SUN))
1379 	{
1380 		core->sound->playSfx("denied");
1381 		return;
1382 	}
1383 
1384 	mb = false;
1385 	this->on = turnON;
1386 	if (on)
1387 	{
1388 		restoreVel = dsq->game->avatar->vel;
1389 		dsq->game->avatar->vel = Vector(0,0,0);
1390 		//dsq->game->avatar->idle();
1391 		dsq->game->togglePause(true);
1392 
1393 		core->sound->playSfx("menu-open");
1394 
1395 		originalActiveTile = activeTile;
1396 
1397 		if (activeTile)
1398 		{
1399 			internalOffset = -activeTile->gridPos;
1400 			if (activeTile->layer == 1)
1401 				scale = Vector(1.5,1.5);
1402 			else
1403 				scale = Vector(1,1);
1404 			if (visMethod == VIS_WRITE)
1405 			{
1406 				// Texture isn't updated while moving, so force an update here
1407 				clearVis(activeTile);
1408 				setVis(activeTile);
1409 			}
1410 		}
1411 
1412 		xMin = xMax = -internalOffset.x;
1413 		yMin = yMax = -internalOffset.y;
1414 		for (int i = 0; i < dsq->continuity.worldMap.getNumWorldMapTiles(); i++)
1415 		{
1416 			WorldMapTile *tile = dsq->continuity.worldMap.getWorldMapTile(i);
1417 			if (tile && (tile->revealed || tile->prerevealed) && tile->q)
1418 			{
1419 				Quad *q = tile->q;
1420 				const float width = q->getWidth() * q->scale.x;
1421 				const float height = q->getHeight() * q->scale.y;
1422 				if (xMin > tile->gridPos.x - width/2)
1423 					xMin = tile->gridPos.x - width/2;
1424 				if (xMax < tile->gridPos.x + width/2)
1425 					xMax = tile->gridPos.x + width/2;
1426 				if (yMin > tile->gridPos.y - height/2)
1427 					yMin = tile->gridPos.y - height/2;
1428 				if (yMax < tile->gridPos.y + height/2)
1429 					yMax = tile->gridPos.y + height/2;
1430 			}
1431 		}
1432 
1433 		if (bg)
1434 			bg->alpha.interpolateTo(1, 0.2);
1435 
1436 		alpha.interpolateTo(1, 0.2);
1437 
1438 
1439 		//dsq->game->hudUnderlay->alpha.interpolateTo(WORLDMAP_UNDERLAY_ALPHA, 0.2);
1440 		underlay->alpha.interpolateTo(WORLDMAP_UNDERLAY_ALPHA, 0.2);
1441 
1442 		addHintQuad1->alpha.interpolateTo(1.0, 0.2);
1443 		addHintQuad2->alpha.interpolateTo(1.0, 0.2);
1444 		helpButton->alpha.interpolateTo(1.0, 0.2);
1445 
1446 		addAllGems();
1447 
1448 		for (Continuity::Beacons::reverse_iterator i = dsq->continuity.beacons.rbegin(); i != dsq->continuity.beacons.rend(); i++)
1449 		{
1450 			if ((*i).on)
1451 			{
1452 				BeaconRender *b = new BeaconRender(&(*i));
1453 				//b->position = (*i).pos;
1454 				//game->addRenderObject(b, layer+1);
1455 				addChild(b, PM_POINTER);
1456 				beaconRenders.push_back(b);
1457 			}
1458 		}
1459 
1460 		inputDelay = 0.5;
1461 	}
1462 	else if (!on)
1463 	{
1464 		inputDelay = 0.5;
1465 
1466 		if (originalActiveTile && activeTile)
1467 		{
1468 			if (activeTile != originalActiveTile)
1469 			{
1470 				if(revMethod == REVEAL_DEFAULT)
1471 				{
1472 					clearVis(activeTile);
1473 					setVis(originalActiveTile);
1474 				}
1475 				activeTile = originalActiveTile;
1476 				activeQuad = activeTile->q;
1477 			}
1478 		}
1479 
1480 		int num = dsq->continuity.worldMap.getNumWorldMapTiles();
1481 		for (int i = 0; i < num; i++)
1482 		{
1483 			WorldMapTile *tile = dsq->continuity.worldMap.getWorldMapTile(i);
1484 			setProperTileColor(tile);
1485 		}
1486 
1487 		// again to set the correct color
1488 		// lame, don't do that
1489 		//setVis(activeTile);
1490 
1491 		// just set the color
1492 		if (activeTile)
1493 		{
1494 			activeTile->q->color = Vector(1,1,1);
1495 			activeTile->q->alphaMod = 1;
1496 		}
1497 
1498 
1499 		//setVis(activeTile);
1500 		/*
1501 		for (int i = 0; i < LR_MENU; i++)
1502 		{
1503 			RenderObjectLayer *rl = dsq->getRenderObjectLayer(i);
1504 			rl->visible = true;
1505 		}
1506 		*/
1507 
1508 		core->sound->playSfx("Menu-Close");
1509 
1510 		if (bg)
1511 			bg->alpha.interpolateTo(0, 0.2);
1512 
1513 		alpha.interpolateTo(0, 0.2);
1514 
1515 		dsq->game->togglePause(false);
1516 		//dsq->game->hudUnderlay->alpha.interpolateTo(0, 0.2);
1517 		underlay->alpha.interpolateTo(0, 0.2);
1518 		addHintQuad1->alpha.interpolateTo(0, 0.2);
1519 		addHintQuad2->alpha.interpolateTo(0, 0.2);
1520 		helpButton->alpha.interpolateTo(0, 0.2);
1521 
1522 
1523 		for (GemMovers::iterator i = gemMovers.begin(); i != gemMovers.end(); i++)
1524 		{
1525 			//removeChild(*i);
1526 			(*i)->safeKill();
1527 		}
1528 		gemMovers.clear();
1529 
1530 		for (BeaconRenders::iterator i = beaconRenders.begin(); i != beaconRenders.end(); i++)
1531 		{
1532 			//removeChild(*i);
1533 			(*i)->safeKill();
1534 		}
1535 		beaconRenders.clear();
1536 
1537 		dsq->game->avatar->vel = restoreVel;
1538 	}
1539 }
1540 
createGemHint(const std::string & gfx)1541 void WorldMapRender::createGemHint(const std::string &gfx)
1542 {
1543 	std::string useString = dsq->getUserInputString(dsq->continuity.stringBank.get(860), "", true);
1544 	if (!useString.empty())
1545 	{
1546 		doubleClickTimer = 0;
1547 		GemData *g = dsq->continuity.pickupGem(gfx, false);
1548 		g->canMove = 1;
1549 		g->pos = getAvatarWorldMapPosition();// + Vector(0, -20);
1550 		g->userString = useString;
1551 		addGem(g);
1552 		fixGems();
1553 	}
1554 }
1555 
updateEditor()1556 void WorldMapRender::updateEditor()
1557 {
1558 	std::ostringstream os;
1559 	os << "EDITING... ";
1560 	if(activeTile)
1561 	{
1562 		os << "x=" << activeTile->gridPos.x << "; y=" << activeTile->gridPos.y << std::endl;
1563 		os << "scale=" << activeTile->scale << "; scale2=" << activeTile->scale2;
1564 	}
1565 	areaLabel->setText(os.str());
1566 }
1567 
action(int id,int state)1568 void WorldMapRender::action (int id, int state)
1569 {
1570 	if (isOn())
1571 	{
1572 		if (id == ACTION_TOGGLEHELPSCREEN && !state)
1573 		{
1574 			onToggleHelpScreen();
1575 		}
1576 		if (id == ACTION_TOGGLEWORLDMAPEDITOR && !state)
1577 		{
1578 			if (dsq->canOpenEditor())
1579 			{
1580 				editorActive = !editorActive;
1581 
1582 				if (editorActive)
1583 				{
1584 					updateEditor();
1585 				}
1586 			}
1587 		}
1588 
1589 		if (id == ACTION_PRIMARY && state)
1590 		{
1591 			if (addHintQuad1->isCoordinateInRadius(core->mouse.position, 10))
1592 			{
1593 				createGemHint("pyramidyellow");
1594 			}
1595 			if (addHintQuad2->isCoordinateInRadius(core->mouse.position, 10))
1596 			{
1597 				createGemHint("pyramidpurple");
1598 			}
1599 		}
1600 
1601 		if (id == ACTION_SECONDARY && !state)
1602 		{
1603 			if (!mover)
1604 			{
1605 				for (GemMovers::iterator i = gemMovers.begin(); i != gemMovers.end(); i++)
1606 				{
1607 					if ((*i)->canMove && (core->mouse.position - (*i)->getWorldPosition()).isLength2DIn(GEM_GRAB))
1608 					{
1609 						removeGem(*i);
1610 						break;
1611 					}
1612 				}
1613 			}
1614 
1615 		}
1616 
1617 		/*
1618 		if (id == ACTION_PRIMARY && state)
1619 		{
1620 			if (doubleClickTimer > 0)
1621 			{
1622 				doubleClickTimer = 0;
1623 				GemData *g = dsq->continuity.pickupGem("pyramidyellow", false);
1624 				g->canMove = 1;
1625 				g->userString = dsq->getUserInputString("Enter Map Hint Name:", "");
1626 				addGem(g);
1627 			}
1628 			else
1629 			{
1630 				if (doubleClickTimer == 0)
1631 				{
1632 					doubleClickTimer = DOUBLE_CLICK_DELAY;
1633 				}
1634 			}
1635 		}
1636 		*/
1637 	}
1638 }
1639