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 "../BBGE/Gradient.h"
22 #include "../BBGE/AfterEffect.h"
23 #include "../BBGE/MathFunctions.h"
24 #include "../BBGE/DebugFont.h"
25 #include "../BBGE/LensFlare.h"
26 #include "../BBGE/RoundedRect.h"
27 #include "../BBGE/SimpleIStringStream.h"
28 
29 #include "Game.h"
30 #include "GridRender.h"
31 #include "WaterSurfaceRender.h"
32 #include "ScriptedEntity.h"
33 #include "AutoMap.h"
34 #include "FlockEntity.h"
35 #include "SchoolFish.h"
36 #include "Avatar.h"
37 #include "Shot.h"
38 #include "Web.h"
39 #include "StatsAndAchievements.h"
40 
41 #include "ToolTip.h"
42 
43 std::vector<std::string> allowedMaps;
44 
45 Vector worldLeftCenter(217,250), worldRightCenter(575, 250);
46 Vector opt_save_original = Vector(350, 350), opt_cancel_original = Vector(450, 350);
47 
48 const float bgSfxVol	= 1.0;
49 
50 const float MENUPAGETRANSTIME		= 0.2; // 0.2
51 
52 const int foodPageSize = 16;
53 const int treasurePageSize = 16;
54 
55 int FoodSlot::foodSlotIndex = -1;
56 
57 int selectedTreasureFlag = -1;
58 
59 std::vector<FoodHolder*>	foodHolders;
60 std::vector<PetSlot*>		petSlots;
61 
62 
getSceneFilename(const std::string & scene)63 std::string getSceneFilename(const std::string &scene)
64 {
65 	if (dsq->mod.isActive())
66 		return std::string(dsq->mod.getPath() + "maps/" + scene + ".xml");
67 	else
68 		return std::string("data/maps/"+scene+".xml");
69 	return "";
70 }
71 
PetSlot(int pet)72 PetSlot::PetSlot(int pet) : AquariaGuiQuad()
73 {
74 	PetData *p = dsq->continuity.getPetData(pet);
75 	if (p)
76 	{
77 		std::string fn = "collectibles/egg-" + p->namePart;
78 		setTexture(fn);
79 	}
80 	scale = Vector(0.9, 0.9);
81 	petidx = pet;
82 	mouseDown = false;
83 	petFlag = FLAG_PET_NAMESTART + petidx;
84 	wasSlot = false;
85 }
86 
onUpdate(float dt)87 void PetSlot::onUpdate(float dt)
88 {
89 	AquariaGuiQuad::onUpdate(dt);
90 
91 	if (!dsq->continuity.getFlag(petFlag))
92 	{
93 		if (!wasSlot)
94 		{
95 			setTexture("gui/wok");
96 			setWidthHeight(80);
97 			wasSlot = true;
98 		}
99 		//alphaMod = 0;
100 		return;
101 	}
102 	else
103 	{
104 		alphaMod = 1;
105 
106 		if (wasSlot)
107 		{
108 			PetData *p = dsq->continuity.getPetData(petidx);
109 			if (p)
110 			{
111 				std::string fn = "collectibles/egg-" + p->namePart;
112 				setTexture(fn);
113 			}
114 			wasSlot = false;
115 		}
116 	}
117 
118 	if (dsq->continuity.getFlag(FLAG_PET_ACTIVE) == petFlag)
119 	{
120 		color = Vector(1,1,1);
121 	}
122 	else
123 		color = Vector(0.5, 0.5, 0.5);
124 
125 	if (alpha.x < 1) return;
126 
127 	if ((core->mouse.position - getWorldPosition()).isLength2DIn(32))
128 	{
129 		scale.interpolateTo(Vector(1.2, 1.2), 0.1);
130 
131 		if (core->mouse.buttons.left && !mouseDown)
132 		{
133 			mouseDown = true;
134 		}
135 		else if (!core->mouse.buttons.left && mouseDown)
136 		{
137 			dsq->sound->playSfx("click");
138 
139 			if (dsq->continuity.getFlag(FLAG_PET_ACTIVE) == petFlag)
140 			{
141 				dsq->game->setActivePet(0);
142 				dsq->sound->playSfx("pet-on");
143 			}
144 			else
145 			{
146 				dsq->game->setActivePet(FLAG_PET_NAMESTART + petidx);
147 				dsq->sound->playSfx("pet-off");
148 			}
149 			mouseDown = false;
150 		}
151 	}
152 	else
153 	{
154 		mouseDown = false;
155 		scale.interpolateTo(Vector(0.9, 0.9), 0.1);
156 	}
157 }
158 
FoodHolder(int slot,bool trash)159 FoodHolder::FoodHolder(int slot, bool trash) : Quad(), slot(slot), trash(trash)
160 {
161 	foodHolderIngredient = 0;
162 	buttonDown = false;
163 
164 	//setTexture("Gui/wok");
165 	renderQuad = false;
166 
167 	wok = new Quad;
168 	if (trash)
169 		wok->setTexture("gui/wok-drop");
170 	else
171 		wok->setTexture("gui/wok");
172 	addChild(wok, PM_POINTER, RBP_ON);
173 
174 	ing = new Quad;
175 	ing->renderQuad = false;
176 	addChild(ing, PM_POINTER);
177 
178 	lid = new Quad("gui/wok-lid", Vector(0,0));
179 	lid->alpha = 0;
180 	lid->alphaMod = 0.5;
181 	addChild(lid, PM_POINTER);
182 }
183 
animateLid(bool down,bool longAnim)184 void FoodHolder::animateLid(bool down, bool longAnim)
185 {
186 	float t = 0.2;
187 
188 	if (!longAnim)
189 	{
190 		t = 0.1;
191 	}
192 
193 	if (down)
194 	{
195 		dsq->sound->playSfx("bubble-lid");
196 		lid->alpha.interpolateTo(1, t);
197 		dsq->main(t);
198 	}
199 	else
200 	{
201 		lid->alpha.interpolateTo(0, t);
202 	}
203 }
204 
isTrash()205 bool FoodHolder::isTrash()
206 {
207 	return trash;
208 }
209 
isEmpty()210 bool FoodHolder::isEmpty()
211 {
212 	return (foodHolderIngredient == 0);
213 }
214 
getIngredient()215 IngredientData *FoodHolder::getIngredient()
216 {
217 	return foodHolderIngredient;
218 }
219 
setIngredient(IngredientData * i,bool effects)220 void FoodHolder::setIngredient(IngredientData *i, bool effects)
221 {
222 	IngredientData *oldi = foodHolderIngredient;
223 	foodHolderIngredient = i;
224 
225 	if (oldi) {
226 		if (oldi->held > 0)
227 			oldi->held --;
228 		oldi->amount ++;
229 	}
230 
231 	if (!i)
232 	{
233 		//ing->scale.interpolateTo(Vector(0,0), 0.1);
234 		ing->renderQuad = false;
235 		//setTexture("Gui/wok");
236 		if (oldi && effects)
237 		{
238 			core->sound->playSfx("Drop");
239 		}
240 
241 		game->enqueuePreviewRecipe();
242 	}
243 	else
244 	{
245 		i->held ++;
246 		if (i->amount > 0)
247 			i->amount --;
248 
249 		ing->setTexture("Ingredients/" + i->gfx);
250 		ing->renderQuad = true;
251 		if (effects)
252 		{
253 			core->sound->playSfx("Wok");
254 
255 			ing->scale.ensureData();
256 			ing->scale.data->path.clear();
257 			ing->scale.data->path.addPathNode(Vector(1,1),0);
258 			ing->scale.data->path.addPathNode(Vector(1.25,1.25), 0.2);
259 			ing->scale.data->path.addPathNode(Vector(1,1),1);
260 			ing->scale.startPath(0.5);
261 		}
262 
263 		game->enqueuePreviewRecipe();
264 	}
265 }
266 
enqueuePreviewRecipe()267 void Game::enqueuePreviewRecipe()
268 {
269 	enqueuedPreviewRecipe = 1;
270 }
271 
updatePreviewRecipe()272 void Game::updatePreviewRecipe()
273 {
274 	const float t = 0.2;
275 
276 	updateCookList();
277 
278 	if (cookList.size() < 2 || recipeMenu.on){
279 		previewRecipe->alpha.interpolateTo(0, t);
280 	}
281 	else{
282 		Recipe *r = findRecipe(cookList);
283 
284 		IngredientData *data=0;
285 
286 		if (r && r->isKnown())
287 		{
288 			data = dsq->continuity.getIngredientDataByName(r->result);
289 			previewRecipe->setTexture("ingredients/"+data->gfx);
290 		}
291 		else
292 		{
293 			previewRecipe->setTexture("gui/question-mark");
294 		}
295 
296 		previewRecipe->alpha.interpolateTo(1, t);
297 
298 	}
299 }
300 
dropFood()301 void FoodHolder::dropFood()
302 {
303 	if (foodHolderIngredient)
304 	{
305 		setIngredient(0);
306 		dsq->game->refreshFoodSlots(true);
307 	}
308 }
309 
onUpdate(float dt)310 void FoodHolder::onUpdate(float dt)
311 {
312 	Quad::onUpdate(dt);
313 
314 	if (!dsq->game->recipeMenu.on && foodHolderIngredient)
315 	{
316 		if ((core->mouse.position - getWorldPosition()).isLength2DIn(20))
317 		{
318 			if (!buttonDown && core->mouse.buttons.left)
319 			{
320 				dropFood();
321 				buttonDown = true;
322 			}
323 		}
324 
325 		if (!buttonDown && core->mouse.buttons.left)
326 			buttonDown = true;
327 		if (buttonDown && !core->mouse.buttons.left)
328 			buttonDown = false;
329 	}
330 }
331 
FoodSlot(int slot)332 FoodSlot::FoodSlot(int slot) : AquariaGuiQuad(), slot(slot)
333 {
334 	doubleClickDelay = 0;
335 
336 	right = false;
337 
338 	renderQuad = false;
339 
340 	label = new DebugFont(8, "");
341 	label->position = Vector(-2, 9);
342 	addChild(label, PM_POINTER);
343 
344 	inCookSlot = false;
345 
346 	ingredient = 0;
347 
348 	lastIngredient = 0;
349 	lastAmount = 0;
350 
351 	grabTime = 0;
352 
353 	foodSlotIndex = -1;
354 	scaleFactor = 1;
355 
356 	shareAlphaWithChildren = 1;
357 
358 	rmb = 0;
359 
360 }
361 
setOriginalPosition(const Vector & op)362 void FoodSlot::setOriginalPosition(const Vector &op)
363 {
364 	originalPosition = op;
365 }
366 
toggle(bool f)367 void FoodSlot::toggle(bool f)
368 {
369 	if (f)
370 	{
371 		alpha = 1;
372 		alphaMod = 1;
373 		label->alpha = 1;
374 	}
375 	else
376 	{
377 		alpha = 0;
378 		alphaMod = 0;
379 		label->alpha = 0;
380 	}
381 }
382 
refresh(bool effects)383 void FoodSlot::refresh(bool effects)
384 {
385 	int offset = game->currentFoodPage*foodPageSize;
386 	IngredientData *i = dsq->continuity.getIngredientHeldByIndex(offset+slot);
387 	if (i)
388 	{
389 		ingredient = i;
390 
391 		if (i->amount > 0)
392 		{
393 			std::ostringstream os;
394 			if (i->amount > 1)
395 				os << i->amount << "/" << i->maxAmount;
396 			label->setText(os.str());
397 			setTexture("Ingredients/" + i->gfx);
398 			renderQuad = true;
399 		}
400 		else
401 		{
402 			label->setText("");
403 			renderQuad = true;
404 
405 			setTexture("gui/wok");
406 			setWidthHeight(64);
407 		}
408 	}
409 	else
410 	{
411 		ingredient = 0;
412 
413 		label->setText("");
414 		renderQuad = true;
415 		setTexture("gui/wok");
416 		setWidthHeight(64);
417 	}
418 
419 	scale.interpolateTo(Vector(1,1)*scaleFactor,0.001);
420 
421 	if (ingredient != 0 && (i != lastIngredient || (i && i->amount != lastAmount)))
422 	{
423 		if (effects)
424 		{
425 			scale.ensureData();
426 			scale.data->path.clear();
427 			scale.data->path.addPathNode(Vector(1,1)*scaleFactor,0);
428 			scale.data->path.addPathNode(Vector(1.5,1.5)*scaleFactor, 0.2);
429 			scale.data->path.addPathNode(Vector(1,1)*scaleFactor,1);
430 			scale.startPath(0.5);
431 		}
432 	}
433 
434 	lastIngredient = i;
435 	if (i)
436 		lastAmount = i->amount;
437 	else
438 		lastAmount = 0;
439 }
440 
eatMe()441 void FoodSlot::eatMe()
442 {
443 	if (ingredient && !dsq->isNested())
444 	{
445 		for (int i = 0; i < foodHolders.size(); i++)
446 		{
447 			if (!foodHolders[i]->isTrash() && !foodHolders[i]->isEmpty())
448 			{
449 				dsq->sound->playSfx("denied");
450 				foodHolders[i]->dropFood();
451 				return;
452 			}
453 		}
454 
455 		if (!ingredient->effects.empty())
456 		{
457 			bool eaten = dsq->continuity.applyIngredientEffects(ingredient);
458 			if(eaten)
459 			{
460 				ingredient->amount--;
461 				dsq->continuity.removeEmptyIngredients();
462 				dsq->game->refreshFoodSlots(true);
463 			}
464 		}
465 		else
466 		{
467 			dsq->sound->playSfx("denied");
468 			/// don't
469 		}
470 	}
471 }
472 
moveRight()473 void FoodSlot::moveRight()
474 {
475 	if (!ingredient) return;
476 	if (ingredient->amount <= 0) return;
477 
478 	for (int i = foodHolders.size()-1; i >= 0; i--)
479 	{
480 		if (foodHolders[i]->alpha.x > 0 && foodHolders[i]->alphaMod > 0 && foodHolders[i]->isEmpty() && !foodHolders[i]->isTrash())
481 		{
482 			foodHolders[i]->setIngredient(ingredient);
483 			inCookSlot = true;
484 			refresh(true);
485 			break;
486 		}
487 	}
488 }
489 
discard()490 void FoodSlot::discard()
491 {
492 	if (!ingredient) return;
493 	if (ingredient->amount <= 0) return;
494 
495 	ingredient->amount--;
496 	dsq->game->dropIngrNames.push_back(ingredient->name);
497 	dsq->continuity.removeEmptyIngredients();
498 	dsq->game->refreshFoodSlots(true);
499 }
500 
isCursorIn()501 bool FoodSlot::isCursorIn()
502 {
503 	return (core->mouse.position - getWorldPosition()).isLength2DIn(32);
504 }
505 
onUpdate(float dt)506 void FoodSlot::onUpdate(float dt)
507 {
508 	AquariaGuiQuad::onUpdate(dt);
509 
510 	if (doubleClickDelay > 0)
511 	{
512 		doubleClickDelay -= dt;
513 		if (doubleClickDelay < 0) doubleClickDelay = 0;
514 	}
515 
516 	if (alphaMod==1 && ingredient && ingredient->amount > 0)
517 	{
518 		if (foodSlotIndex == slot)
519 		{
520 			//grabTime += dt;
521 			if (!core->mouse.buttons.left)
522 			{
523 				foodSlotIndex = -1;
524 
525 				//if (ingredient->type < IT_FOOD)
526 
527 				//if (grabTime > 0.5f)
528 				if (!dsq->game->recipeMenu.on)
529 				{
530 					/*
531 					dsq->game->removeRenderObject(this);
532 					dsq->game->addRenderObject(this, LR_MENU);
533 					*/
534 
535 
536 					Vector wp = getWorldPosition();
537 					if ((dsq->game->lips->getWorldPosition() - wp).isLength2DIn(32))
538 					{
539 						dsq->menuSelectDelay = 0.5;
540 
541 						eatMe();
542 					}
543 					else if (wp.x < 40 || wp.y < 40 || wp.x > 760 || wp.y > 560)
544 					{
545 						discard();
546 					}
547 					else
548 					{
549 						bool droppedIn = false;
550 						for (int i = 0; i < foodHolders.size(); i++)
551 						{
552 							bool in = (foodHolders[i]->getWorldPosition() - wp).isLength2DIn(32);
553 							if (in)
554 							{
555 								droppedIn = true;
556 
557 								if (foodHolders[i]->isTrash())
558 								{
559 									discard();
560 
561 									dsq->game->foodLabel->alpha.interpolateTo(0, 2);
562 									dsq->game->foodDescription->alpha.interpolateTo(0, 2);
563 
564 									break;
565 									//return;
566 								}
567 								else if (foodHolders[i]->isEmpty())
568 								{
569 									foodHolders[i]->setIngredient(ingredient);
570 									inCookSlot = true;
571 									refresh(true);
572 									break;
573 								}
574 							}
575 						}
576 
577 						if (!droppedIn)
578 						{
579 							if (doubleClickDelay > 0)
580 							{
581 								dsq->menuSelectDelay = 0.5;
582 								doubleClickDelay = 0;
583 								eatMe();
584 
585 								//if (!originalPosition.isZero())
586 								position = originalPosition;
587 
588 								label->alpha = 1;
589 								grabTime = 0;
590 
591 								return;
592 							}
593 							else
594 							{
595 								doubleClickDelay = DOUBLE_CLICK_DELAY;
596 							}
597 						}
598 					}
599 				}
600 				/*
601 				else
602 				{
603 					if (ingredient)
604 						debugLog(splitCamelCase(ingredient->name));
605 				}
606 				*/
607 
608 				//if (!originalPosition.isZero())
609 				position = originalPosition;
610 
611 				label->alpha = 1;
612 
613 				grabTime = 0;
614 			}
615 			else
616 			{
617 				if (!dsq->game->recipeMenu.on)
618 				{
619 					if (dsq->inputMode == INPUT_MOUSE)
620 					{
621 						Vector diff = core->mouse.position - getWorldPosition();
622 						position += diff;
623 						dsq->game->moveFoodSlotToFront = this;
624 					}
625 				}
626 				//position = parent->getWorldCollidePosition(core->mouse.position);
627 				//position = core->mouse.position;
628 			}
629 		}
630 
631 		if ((core->mouse.position - getWorldPosition()).isLength2DIn(16))
632 		//if (isCursorIn())
633 		{
634 			dsq->game->foodLabel->setText(ingredient->displayName);
635 			dsq->game->foodLabel->alpha.interpolateTo(1, 0.2);
636 
637 			dsq->game->foodDescription->setText(dsq->continuity.getIngredientAffectsString(ingredient));
638 			dsq->game->foodDescription->alpha.interpolateTo(1, 0.2);
639 
640 			if (core->mouse.buttons.left && foodSlotIndex == -1)
641 			{
642 				grabTime = 0;
643 				foodSlotIndex = slot;
644 				label->alpha = 0;
645 
646 				/*
647 				dsq->game->removeRenderObject(this);
648 				dsq->game->addRenderObject(this, LR_HUD);
649 				*/
650 
651 				if (!inCookSlot)
652 				{
653 					originalPosition = position;
654 				}
655 			}
656 
657 			if (core->mouse.buttons.right && !rmb)
658 			{
659 				rmb = 1;
660 			}
661 			else if (!core->mouse.buttons.right && rmb)
662 			{
663 				rmb = 0;
664 				if (!game->recipeMenu.on)
665 					moveRight();
666 				return;
667 			}
668 
669 			/*
670 			if (core->mouse.buttons.right && !right)
671 			{
672 				right = true;
673 			}
674 			else if (!core->mouse.buttons.right && right)
675 			{
676 				right = false;
677 
678 				bool dropped = false;
679 				for (int i = foodHolders.size()-1; i >= 0; i--)
680 				{
681 					if (foodHolders[i]->alpha.x > 0 && foodHolders[i]->alphaMod > 0 && foodHolders[i]->isEmpty() && !foodHolders[i]->isTrash())
682 					{
683 						foodHolders[i]->setIngredient(ingredient);
684 						inCookSlot = true;
685 						refresh();
686 						dropped = true;
687 						break;
688 					}
689 				}
690 
691 				if (dropped)
692 				{
693 				}
694 				else
695 				{
696 					core->sound->playSfx("denied");
697 				}
698 			}
699 			*/
700 		}
701 		else
702 		{
703 			if (!dsq->game->foodLabel->alpha.isInterpolating())
704 				dsq->game->foodLabel->alpha.interpolateTo(0, 2);
705 			if (!dsq->game->foodDescription->alpha.isInterpolating())
706 				dsq->game->foodDescription->alpha.interpolateTo(0, 2);
707 			rmb = 0;
708 		}
709 	}
710 	else
711 	{
712 		rmb = 0;
713 	}
714 }
715 
SongSlot(int songSlot)716 SongSlot::SongSlot(int songSlot) : AquariaGuiQuad(), songSlot(songSlot)
717 {
718 	songType = dsq->continuity.getSongTypeBySlot(songSlot);
719 	std::ostringstream os;
720 	os << "Song/SongSlot-" << songSlot;
721 	setTexture(os.str());
722 
723 	glow = new Quad("particles/glow", Vector(0,0));
724 	glow->setWidthHeight(128, 128);
725 	glow->setBlendType(RenderObject::BLEND_ADD);
726 	glow->alpha = 0;
727 	addChild(glow, PM_POINTER);
728 
729 	mbDown = false;
730 
731 	if (dsq->continuity.isSongTypeForm((SongType)dsq->continuity.getSongTypeBySlot(songSlot)))
732 		scale = Vector(0.9, 0.9);
733 	else
734 		scale = Vector(0.6, 0.6);
735 }
736 
onUpdate(float dt)737 void SongSlot::onUpdate(float dt)
738 {
739 	AquariaGuiQuad::onUpdate(dt);
740 
741 	if (alpha.x == 1 && alphaMod == 1 && (!parent || parent->alpha.x == 1))
742 	{
743 		if ((core->mouse.position - getWorldPosition()).isLength2DIn(24))
744 		{
745 			dsq->game->playSongInMenu(songType);
746 			dsq->game->songLabel->setText(dsq->continuity.getSongNameBySlot(songSlot));
747 			dsq->game->songLabel->alpha.interpolateTo(1, 0.2);
748 			const bool anyButton = core->mouse.buttons.left || core->mouse.buttons.right;
749 			if (!mbDown && anyButton)
750 			{
751 				mbDown = true;
752 			}
753 			else if (mbDown && !anyButton)
754 			{
755 				mbDown = false;
756 
757 				dsq->game->playSongInMenu(songType, 1);
758 				if (!dsq->sound->isPlayingVoice())
759 					dsq->voice(dsq->continuity.getVoxForSongSlot(songSlot));
760 				//dsq->game->songDescription->setText(dsq->continuity.getDescriptionForSongSlot(songSlot));
761 
762 			}
763 			glow->alpha.interpolateTo(0.2, 0.15);
764 		}
765 		else
766 		{
767 			mbDown = false;
768 			glow->alpha.interpolateTo(0, 0.2);
769 			if (!dsq->game->songLabel->alpha.isInterpolating())
770 			{
771 				dsq->game->songLabel->alpha.interpolateTo(0, 2);
772 				/*
773 				dsq->game->songLabel->alpha.path.addPathNode(dsq->game->songLabel->alpha, 0);
774 				dsq->game->songLabel->alpha.path.addPathNode(dsq->game->songLabel->alpha, 0.5);
775 				dsq->game->songLabel->alpha.path.addPathNode(0, 1);
776 				dsq->game->songLabel->alpha.startPath(3);
777 				*/
778 			}
779 		}
780 	}
781 }
782 
783 const int treasureFlagStart			= 500;
784 
TreasureSlot(int index)785 TreasureSlot::TreasureSlot(int index) : AquariaGuiQuad()
786 {
787 	this->index = index;
788 	mbd = false;
789 	flag = 0;
790 	doubleClickTimer = 0;
791 }
792 
onUpdate(float dt)793 void TreasureSlot::onUpdate(float dt)
794 {
795 	AquariaGuiQuad::onUpdate(dt);
796 
797 	doubleClickTimer -= dt;
798 	if (doubleClickTimer < 0)
799 		doubleClickTimer = 0;
800 
801 	if (alphaMod == 1 && alpha.x == 1 && flag != 0)
802 	{
803 		if ((core->mouse.position - getWorldPosition()).isLength2DIn(18))
804 		{
805 			scale.interpolateTo(Vector(1.2, 1.2), 0.1);
806 			if (core->mouse.buttons.left && !mbd)
807 			{
808 				mbd = true;
809 			}
810 			else if (!core->mouse.buttons.left && mbd)
811 			{
812 				mbd = false;
813 
814 				if (doubleClickTimer > 0)
815 				{
816 					doubleClickTimer = 0;
817 
818 					dsq->game->onUseTreasure(flag);
819 				}
820 				else
821 				{
822 					dsq->sound->playSfx("treasure-select", 0.5);
823 					dsq->spawnParticleEffect("menu-switch", worldRightCenter, 0, 0, LR_HUD3, 1);
824 
825 
826 
827 					dsq->game->treasureLabel->setText(treasureName);
828 					dsq->game->treasureLabel->alpha = 1;
829 					dsq->game->treasureCloseUp->setTexture(dsq->continuity.treasureData[flag].gfx);
830 					//dsq->game->treasureCloseUp->scale = Vector(dsq->continuity.treasureData[flag].sz, dsq->continuity.treasureData[flag].sz);
831 
832 					dsq->game->treasureCloseUp->alpha = 1;
833 
834 					dsq->game->treasureDescription->setText(treasureDesc, Vector(400,450), 400);
835 					dsq->game->treasureDescription->alpha = 1;
836 
837 					dsq->game->use->alpha = dsq->continuity.treasureData[flag].use;
838 
839 					/*
840 					dsq->game->treasureCloseUp->scale = Vector(0.5,0.5);
841 					dsq->game->treasureCloseUp->scale.interpolateTo(Vector(1,1), 0.2);
842 					dsq->game->treasureCloseUp->alpha = 0.1;
843 					dsq->game->treasureCloseUp->alpha.interpolateTo(1, 0.2);
844 					*/
845 
846 					selectedTreasureFlag = flag;
847 
848 					doubleClickTimer = 0.2;
849 
850 
851 					std::ostringstream os;
852 					os << "treasure flag: " << flag << " desc: " << treasureDesc;
853 					debugLog(os.str());
854 				}
855 			}
856 		}
857 		else
858 		{
859 			mbd = false;
860 			scale.interpolateTo(Vector(1, 1), 0.1);
861 		}
862 	}
863 	else
864 	{
865 		mbd = false;
866 		scale.interpolateTo(Vector(1, 1), 0.001);
867 	}
868 }
869 
refresh()870 void TreasureSlot::refresh()
871 {
872 	flag = (game->currentTreasurePage*treasurePageSize) + index + treasureFlagStart;
873 	if (flag >= FLAG_COLLECTIBLE_START && flag < FLAG_COLLECTIBLE_END && dsq->continuity.getFlag(flag)>0)
874 	{
875 		// get treasure image somehow
876 		setTexture(dsq->continuity.treasureData[flag].gfx);
877 		float scl = dsq->continuity.treasureData[flag].sz;
878 
879 		float w = width;
880 		float h = height;
881 		float sz = 50;
882 		if (w > h)
883 		{
884 			w = sz;
885 			h = (height*sz)/width;
886 		}
887 		else
888 		{
889 			h = sz;
890 			w = (width*sz)/height;
891 		}
892 
893 		setWidthHeight(w*scl, h*scl);
894 
895 		std::string parse = dsq->continuity.stringBank.get(flag);
896 
897 		int p1 = parse.find_first_of('[');
898 		if (p1 != std::string::npos)
899 		{
900 			p1++;
901 			int p2 = parse.find_first_of(']');
902 			treasureName = parse.substr(p1,p2-p1);
903 
904 			p1 = parse.find_last_of('[');
905 			if (p1 != std::string::npos)
906 			{
907 				p1++;
908 				p2 = parse.find_last_of(']');
909 				treasureDesc = parse.substr(p1,p2-p1);
910 			}
911 		}
912 
913 		alphaMod = 1;
914 	}
915 	else
916 	{
917 		flag = 0;
918 		alphaMod = 1;
919 
920 		setTexture("gui/wok");
921 		setWidthHeight(48);
922 		//alphaMod = 0;
923 	}
924 }
925 
getNearestIngredient(const Vector & pos,int radius)926 Ingredient *Game::getNearestIngredient(const Vector &pos, int radius)
927 {
928 	int closest = -1;
929 	int r2 = sqr(radius);
930 	Ingredient *returnIngredient = 0;
931 
932 	for (Ingredients::iterator i = ingredients.begin(); i != ingredients.end(); i++)
933 	{
934 		int len = (pos - (*i)->position).getSquaredLength2D();
935 		if (len <= r2 && (closest == - 1 || len < closest))
936 		{
937 			closest = len;
938 			returnIngredient = (*i);
939 		}
940 	}
941 	return returnIngredient;
942 }
943 
getNearestEntity(const Vector & pos,int radius,Entity * ignore,EntityType et,DamageType dt,int lrStart,int lrEnd)944 Entity *Game::getNearestEntity(const Vector &pos, int radius, Entity *ignore, EntityType et, DamageType dt, int lrStart, int lrEnd)
945 {
946 	int sqrRadius = radius*radius;
947 	Entity *closest = 0;
948 	int sml=-1;
949 	int dist = 0;
950 	FOR_ENTITIES(i)
951 	{
952 		Entity *e = *i;
953 		dist = (e->position - pos).getSquaredLength2D();
954 		if (dist <= sqrRadius)
955 		{
956 			if (e != ignore && e->isPresent())
957 			{
958 				if (lrStart == -1 || lrEnd == -1 || (e->layer >= lrStart && e->layer <= lrEnd))
959 				{
960 					if (et == ET_NOTYPE || e->getEntityType() == et)
961 					{
962 						if (dt == DT_NONE || e->isDamageTarget(dt))
963 						{
964 							if (sml == -1 || dist < sml)
965 							{
966 								closest = e;
967 								sml = dist;
968 							}
969 						}
970 					}
971 				}
972 			}
973 		}
974 	}
975 	return closest;
976 }
977 
978 /*
979 class Avatar : public Entity
980 {
981 public:
982 	Vector position, myZoom;
983 	void clampPosition();
984 	Entity *convoEntity;
985 	std::string convoToRun;
986 	Entity *attachedTo;
987 	Quad *burstBar;
988 	int health;
989 	bool isCharging();
990 	bool isEntityDead();
991 	int maxHealth, mana, maxMana;
992 	bool zoomOverriden;
993 
994 };
995 */
996 
997 /*
998 #include "JetStream.h"
999 #include "Rock.h"
1000 #include "SchoolFish.h"
1001 */
1002 /*
1003 #include "Game.h"
1004 #include "AfterEffect.h"
1005 #include "Button.h"
1006 #include "TextBox.h"
1007 #include "LightShaft.h"
1008 #include "Item.h"
1009 
1010 #include "Elements.h"
1011 #include "WavyWeed.h"
1012 #include "BitmapFont.h"
1013 
1014 #include "ParticleEffects.h"
1015 
1016 
1017 
1018 // SPECIAL
1019 */
1020 
1021 Vector menuBgScale;
1022 
1023 const int ITEMS_PER_PAGE = 12;
1024 
ObsRow(int tx,int ty,int len)1025 ObsRow::ObsRow(int tx, int ty, int len) : tx(tx), ty(ty), len(len)
1026 {
1027 }
1028 
getNumberOfEntitiesNamed(const std::string & name)1029 int Game::getNumberOfEntitiesNamed(const std::string &name)
1030 {
1031 	int c = 0;
1032 	FOR_ENTITIES(i)
1033 	{
1034 		Entity *e = *i;
1035 		if (e->life == 1 && (nocasecmp(e->name, name)==0))
1036 			c++;
1037 	}
1038 	return c;
1039 }
1040 
playSongInMenu(int songType,bool override)1041 void Game::playSongInMenu(int songType, bool override)
1042 {
1043 	if (playingSongInMenu == -1 || override)
1044 	{
1045 		playingSongInMenu = songType;
1046 		currentSongMenuNote = 0;
1047 		songMenuPlayDelay = 0.5;
1048 	}
1049 }
1050 
flipRenderObjectVertical(RenderObject * r,int flipY)1051 void Game::flipRenderObjectVertical(RenderObject *r, int flipY)
1052 {
1053 	if (r->position.y < flipY)
1054 		r->position.y = flipY + (flipY-r->position.y);
1055 	else
1056 		r->position.y = flipY - (r->position.y-flipY);
1057 }
1058 
isSceneFlipped()1059 bool Game::isSceneFlipped()
1060 {
1061 	return sceneFlipped;
1062 }
1063 
flipSceneVertical(int flipY)1064 void Game::flipSceneVertical(int flipY)
1065 {
1066 	sceneFlipped = !sceneFlipped;
1067 	dsq->screenTransition->capture();
1068 	dsq->render();
1069 	dsq->screenTransition->go(1);
1070 
1071 	FOR_ENTITIES(itr)
1072 	{
1073 		Entity *e = *itr;
1074 		flipRenderObjectVertical(e, flipY);
1075 	}
1076 	int i = 0;
1077 	int flipTY = (flipY/TILE_SIZE)-1;
1078 	for (i = 0; i < obsRows.size(); i++)
1079 	{
1080 		if (obsRows[i].ty < flipTY)
1081 			obsRows[i].ty = flipTY + (flipTY - obsRows[i].ty);
1082 		else
1083 			obsRows[i].ty = flipTY - (obsRows[i].ty - flipTY);
1084 	}
1085 	for (i = 0; i < dsq->getNumElements(); i++)
1086 	{
1087 		Element *e = dsq->getElement(i);
1088 		e->rotation.z = 180-e->rotation.z;
1089 		flipRenderObjectVertical(e, flipY);
1090 	}
1091 	/*
1092 	// DUMBASS: avatar is an entity.. it has already been flipped!
1093 	if (dsq->game->avatar)
1094 	{
1095 		flipRenderObjectVertical(dsq->game->avatar, flipY);
1096 		dsq->game->avatar->clampPosition();
1097 		dsq->game->avatar->update(0.03);
1098 	}
1099 	*/
1100 	reconstructGrid();
1101 	FOR_ENTITIES(i)
1102 	{
1103 		Entity *e = *i;
1104 		e->onSceneFlipped();
1105 	}
1106 	reconstructGrid();
1107 	if (cameraFollow)
1108 		warpCameraTo(*cameraFollow);
1109 	dsq->resetTimer();
1110 }
1111 
setMenuDescriptionText(const std::string & text)1112 void Game::setMenuDescriptionText(const std::string &text)
1113 {
1114 	menuDescription->setText(text);
1115 }
1116 
1117 Game *game = 0;
1118 
spawnIngredient(const std::string & ing,const Vector & pos,int times,int out)1119 Ingredient *Game::spawnIngredient(const std::string &ing, const Vector &pos, int times, int out)
1120 {
1121 	std::string use = ing;
1122 	Ingredient *i = 0;
1123 	for (int c = 0; c < times; c++)
1124 	{
1125 		//HACK:
1126 		if (nocasecmp(ing, "poultice")==0)
1127 			use = "LeafPoultice";
1128 
1129 		IngredientData *d = dsq->continuity.getIngredientDataByName(use);
1130 		if (d)
1131 		{
1132 			i = new Ingredient(pos, d);
1133 			ingredients.push_back(i);
1134 			if (out)
1135 			{
1136 				/*
1137 				if (i->velocity.y > i->velocity.x)
1138 				{
1139 					i->velocity.x = i->velocity.y;
1140 					i->velocity.y = -500;
1141 				}
1142 				if (i->velocity.y > 0)
1143 					i->velocity.y *= -1;
1144 				*/
1145 
1146 				i->velocity.x = 0;
1147 				i->velocity.y = -500;
1148 			}
1149 			establishEntity(i);
1150 			//addRenderObject(i, LR_ENTITIES);
1151 		}
1152 		else
1153 		{
1154 			debugLog("Could not find ingredient data for [" + use + "]");
1155 		}
1156 	}
1157 	return i;
1158 }
1159 
spawnIngredientFromEntity(Entity * ent,IngredientData * data)1160 void Game::spawnIngredientFromEntity(Entity *ent, IngredientData *data)
1161 {
1162 	Ingredient *i = new Ingredient(ent->position, data);
1163 	ingredients.push_back(i);
1164 	establishEntity(i);
1165 	//addRenderObject(i, LR_ENTITIES);
1166 }
1167 
Game()1168 Game::Game() : StateObject()
1169 {
1170 	applyingState = false;
1171 	blurEffectsCheck = 0;
1172 	ripplesCheck = 0;
1173 
1174 	cookDelay = 0;
1175 
1176 #if defined(AQUARIA_DEMO)
1177 	allowedMaps.push_back("naijacave");
1178 	allowedMaps.push_back("trainingcave");
1179 	allowedMaps.push_back("mainarea");
1180 	allowedMaps.push_back("vedhacave");
1181 	allowedMaps.push_back("openwater02");
1182 	allowedMaps.push_back("energytemple01");
1183 	allowedMaps.push_back("energytemple02");
1184 	allowedMaps.push_back("energytemple03");
1185 	allowedMaps.push_back("energytemple04");
1186 	allowedMaps.push_back("energytemple05");
1187 	allowedMaps.push_back("energytemple06");
1188 	allowedMaps.push_back("songcave");
1189 	allowedMaps.push_back("songcave02");
1190 	allowedMaps.push_back("title");
1191 	allowedMaps.push_back("energytemplevision");
1192 #endif
1193 
1194 	hasPlayedLow = false;
1195 
1196 	invincibleOnNested = true;
1197 	activation = false;
1198 	invinciblity = false;
1199 
1200 	active = false;
1201 
1202 	registerState(this, "Game");
1203 
1204 	optionsOnly = false;
1205 
1206 	toFlip = -1;
1207 	shuttingDownGameState = false;
1208 	dsq->loops.bg = BBGE_AUDIO_NOCHANNEL;
1209 	dsq->loops.bg2 = BBGE_AUDIO_NOCHANNEL;
1210 
1211 
1212 	loadingScene = false;
1213 	controlHint_mouseLeft = controlHint_mouseRight = controlHint_mouseMiddle = controlHint_mouseBody = controlHint_bg = 0;
1214 	controlHint_text = 0;
1215 
1216 	avatar = 0;
1217 	fromVel = Vector(0,-1);
1218 	currentInventoryPage = 0;
1219 	deathTimer = 0;
1220 
1221 	game = this;
1222 	elementWithMenu = 0;
1223 	cameraFollow = 0;
1224 
1225 	worldMapRender = 0;
1226 
1227 	for (int i = 0; i < PATH_MAX; i++)
1228 		firstPathOfType[i] = 0;
1229 
1230 	loadEntityTypeList();
1231 
1232 	lastCollideMaskIndex = -1;
1233 	worldPaused = false;
1234 
1235 	cookingScript = 0;
1236 
1237 }
1238 
~Game()1239 Game::~Game()
1240 {
1241 	tileCache.clean();
1242 	game = 0;
1243 }
1244 /*
1245 void Game::doChoiceMenu(Vector position, std::vector<std::string> choices)
1246 {
1247 	dsq->gui.openChoiceMenu(position);
1248 	for (int i = 0; i < choices.size(); i++)
1249 	{
1250 		dsq->gui.choiceMenu.addEntry(choices[i]);
1251 	}
1252 	selectedChoice = "";
1253 	while (selectedChoice.empty())
1254 	{
1255 		dsq->delay(10);
1256 	}
1257 	dsq->gui.closeChoiceMenu();
1258 }
1259 */
1260 
1261 /*
1262 void Game::onAssignMenuScreenItemToSlot0()
1263 {
1264 	if (!dsq->continuity.hudVisible) return;
1265 	if (!selectedMenuScreenItem) return;
1266 	dsq->continuity.setItemSlot(0, selectedMenuScreenItem->getItemIndex());
1267 }
1268 
1269 void Game::onAssignMenuScreenItemToSlot1()
1270 {
1271 	if (!dsq->continuity.hudVisible) return;
1272 	if (!selectedMenuScreenItem) return;
1273 	dsq->continuity.setItemSlot(1, selectedMenuScreenItem->getItemIndex());
1274 }
1275 
1276 void Game::onAssignMenuScreenItemToSlot2()
1277 {
1278 	if (!dsq->continuity.hudVisible) return;
1279 	if (!selectedMenuScreenItem) return;
1280 	dsq->continuity.setItemSlot(2, selectedMenuScreenItem->getItemIndex());
1281 }
1282 
1283 void Game::onAssignMenuScreenItemToSlot3()
1284 {
1285 	if (!dsq->continuity.hudVisible) return;
1286 	if (!selectedMenuScreenItem) return;
1287 	dsq->continuity.setItemSlot(3, selectedMenuScreenItem->getItemIndex());
1288 }
1289 */
1290 
1291 Quad *menu_blackout = 0;
1292 
showInGameMenu(bool ignoreInput,bool optionsOnly,MenuPage menuPage)1293 void Game::showInGameMenu(bool ignoreInput, bool optionsOnly, MenuPage menuPage)
1294 {
1295 	if (avatar && core->getNestedMains()==1 && !avatar->isSinging() && (ignoreInput || avatar->isInputEnabled()))
1296 	{
1297 		//dsq->toggleInputGrabPlat(false);
1298 
1299 		dsq->game->clearControlHint();
1300 
1301 		selectedTreasureFlag = -1;
1302 		this->optionsOnly = optionsOnly;
1303 
1304 		core->sound->playSfx("Menu-Open");
1305 		dropIngrNames.clear();
1306 
1307 		if (avatar->isEntityDead()) return;
1308 
1309 		if (dsq->game->autoMap && dsq->game->autoMap->isOn())
1310 			dsq->game->autoMap->toggle(false);
1311 
1312 		toggleOptionsMenu(false);
1313 		dsq->overlay->alpha.interpolateTo(0, 0.1);
1314 		float t = 0.3;
1315 
1316 
1317 		if (!optionsOnly)
1318 		{
1319 			togglePause(true);
1320 		}
1321 
1322 		if (optionsOnly)
1323 		{
1324 			menu_blackout = new Quad;
1325 			menu_blackout->color = 0;
1326 			menu_blackout->autoWidth = AUTO_VIRTUALWIDTH;
1327 			menu_blackout->autoHeight = AUTO_VIRTUALHEIGHT;
1328 			menu_blackout->followCamera = 1;
1329 			menu_blackout->position = Vector(400,300);
1330 			menu_blackout->alphaMod = 0.75;
1331 			menu_blackout->alpha = 0;
1332 			menu_blackout->alpha.interpolateTo(1, 0.5);
1333 			addRenderObject(menu_blackout, LR_AFTER_EFFECTS);
1334 
1335 			menuBg2->alpha = 0;
1336 		}
1337 		else
1338 		{
1339 			menuBg2->alpha = 0;
1340 			menuBg2->alpha.interpolateTo(1, t*0.5f);
1341 		}
1342 
1343 		if (dsq->continuity.hasFormUpgrade(FORMUPGRADE_ENERGY2))
1344 			energyIdol->alphaMod = 1;
1345 		else
1346 			energyIdol->alphaMod = 0;
1347 
1348 		if (dsq->continuity.getFlag(FLAG_LI) >= 100)
1349 			liCrystal->alphaMod = 1;
1350 		else
1351 			liCrystal->alphaMod = 0;
1352 
1353 		int i = 0;
1354 
1355 
1356 		for (i = 0; i < songSlots.size(); i++)
1357 		{
1358 			if (dsq->continuity.hasSong(dsq->continuity.getSongTypeBySlot(i)))
1359 				songSlots[i]->alpha.interpolateTo(1, t);
1360 			else
1361 				songSlots[i]->alpha = 0;
1362 		}
1363 
1364 
1365 
1366 		/*
1367 		std::ostringstream os;
1368 		os << "Exp: " << dsq->continuity.exp;
1369 		menuEXP->setText(os.str());
1370 		menuEXP->alpha.interpolateTo(1, 0.5);
1371 
1372 		std::ostringstream os2;
1373 		os2 << "Money: " << dsq->continuity.money;
1374 		menuMoney->setText(os2.str());
1375 		menuMoney->alpha.interpolateTo(1, 0.5);
1376 		*/
1377 
1378 		menuDescription->setText("");
1379 
1380 		menuDescription->alpha.interpolateTo(1, t);
1381 
1382 		menuBg->scale = menuBgScale*0.5f;
1383 		menuBg->scale.interpolateTo(menuBgScale, t);
1384 		menuBg->alpha.interpolateTo(1, t*0.5f);
1385 		menuBg->setHidden(false);
1386 
1387 		// FIXME: This gets a little verbose because of all the
1388 		// individual non-child objects.  Is there a reason they
1389 		// can't all be children of menuBg?  --achurch
1390 		opt_save->setHidden(false);
1391 		opt_cancel->setHidden(false);
1392 		options->setHidden(false);
1393 		keyConfigButton->setHidden(false);
1394 		cook->setHidden(false);
1395 		foodSort->setHidden(false);
1396 		recipes->setHidden(false);
1397 		use->setHidden(false);
1398 		prevFood->setHidden(false);
1399 		nextFood->setHidden(false);
1400 		prevTreasure->setHidden(false);
1401 		nextTreasure->setHidden(false);
1402 		circlePageNum->setHidden(false);
1403 		previewRecipe->setHidden(false);
1404 		showRecipe->setHidden(false);
1405 		recipeMenu.scroll->setHidden(false);
1406 		recipeMenu.scrollEnd->setHidden(false);
1407 		recipeMenu.header->setHidden(false);
1408 		recipeMenu.page->setHidden(false);
1409 		recipeMenu.prevPage->setHidden(false);
1410 		recipeMenu.nextPage->setHidden(false);
1411 		menuDescription->setHidden(false);
1412 		eAre->setHidden(false);
1413 		eYes->setHidden(false);
1414 		eNo->setHidden(false);
1415 		menuIconGlow->setHidden(false);
1416 		for (int i = 0; i < menu.size(); i++)
1417 			menu[i]->setHidden(false);
1418 		for (int i = 0; i < treasureSlots.size(); i++)
1419 			treasureSlots[i]->setHidden(false);
1420 		treasureDescription->setHidden(false);
1421 		for (int i = 0; i < foodSlots.size(); i++)
1422 			foodSlots[i]->setHidden(false);
1423 
1424 
1425 		if (dsq->game->miniMapRender)
1426 		{
1427 			dsq->game->miniMapRender->slide(1);
1428 		}
1429 
1430 		toggleMainMenu(false);
1431 
1432 		dsq->main(t);
1433 
1434 		dsq->screenTransition->capture();
1435 
1436 		//toggleMiniMapRender(0);
1437 
1438 		MenuPage useMenuPage = MENUPAGE_NONE;
1439 
1440 		if (!optionsOnly)
1441 		{
1442 			if (menuPage != MENUPAGE_NONE)
1443 			{
1444 				useMenuPage = menuPage;
1445 			}
1446 			else if (dsq->continuity.lastMenuPage != MENUPAGE_NONE)
1447 			{
1448 				//errorLog("setting last menu page");
1449 				useMenuPage = dsq->continuity.lastMenuPage;
1450 			}
1451 		}
1452 
1453 
1454 		switch(useMenuPage)
1455 		{
1456 		case MENUPAGE_FOOD:
1457 			toggleFoodMenu(true);
1458 			((AquariaMenuItem*)menu[6])->setFocus(true);
1459 		break;
1460 		case MENUPAGE_TREASURES:
1461 			toggleTreasureMenu(true);
1462 		break;
1463 		case MENUPAGE_PETS:
1464 			togglePetMenu(true);
1465 		break;
1466 		case MENUPAGE_SONGS:
1467 		default:
1468 		{
1469 			if (optionsOnly)
1470 			{
1471 				toggleOptionsMenu(true);
1472 			}
1473 			else
1474 			{
1475 				float t = 0.1;
1476 
1477 				toggleMainMenu(true);
1478 
1479 				songBubbles->alpha.interpolateTo(1, t);
1480 				if (menuSongs)
1481 				{
1482 					menuSongs->alpha.interpolateTo(1, t);
1483 				}
1484 				for (i = 0; i < menu.size(); i++)
1485 				{
1486 					menu[i]->scale = Vector(0,0);
1487 					menu[i]->alpha = 0;
1488 				}
1489 				((AquariaMenuItem*)menu[5])->setFocus(true);
1490 			}
1491 		}
1492 		}
1493 
1494 
1495 		if (!optionsOnly)
1496 		{
1497 			for (i = 0; i < menu.size(); i++)
1498 			{
1499 				menu[i]->scale.interpolateTo(Vector(1, 1), 0.15);
1500 
1501 				menu[i]->alpha.interpolateTo(1, 0.15);
1502 			}
1503 
1504 			menuIconGlow->alpha.interpolateTo(1, 0.5);
1505 		}
1506 
1507 		menuOpenTimer = 0;
1508 
1509 		inGameMenu = true;
1510 
1511 
1512 
1513 		dsq->routeShoulder = false;
1514 
1515 
1516 		dsq->screenTransition->transition(MENUPAGETRANSTIME);
1517 
1518 
1519 
1520 		if (optionsOnly)
1521 		{
1522 			dsq->main(-1);
1523 		}
1524 	}
1525 }
1526 
pickupIngredientEffects(IngredientData * data)1527 void Game::pickupIngredientEffects(IngredientData *data)
1528 {
1529 	Quad *q = new Quad("gfx/ingredients/" + data->gfx, Vector(800-20 + core->getVirtualOffX(), (570-2*(100*miniMapRender->scale.y))+ingOffY));
1530 	q->scale = Vector(0.8, 0.8);
1531 	q->followCamera = 1;
1532 	q->alpha.ensureData();
1533 	q->alpha.data->path.addPathNode(0, 0);
1534 	q->alpha.data->path.addPathNode(1.0, 0.1);
1535 	q->alpha.data->path.addPathNode(0, 1.0);
1536 	q->alpha.startPath(2);
1537 	q->setLife(1);
1538 	q->setDecayRate(0.5);
1539 	addRenderObject(q, LR_HELP);
1540 	ingOffY -= 40;
1541 	ingOffYTimer = 2;
1542 }
1543 
hideInGameMenu(bool effects,bool cancel)1544 void Game::hideInGameMenu(bool effects, bool cancel)
1545 {
1546 	if (isCooking) return;
1547 	if (FoodSlot::foodSlotIndex != -1) return;
1548 	if (effects && !this->isInGameMenu()) return;
1549 
1550 	if (avatar)
1551 	{
1552 		if (resBox)
1553 			resBox->close();
1554 
1555 		//dsq->toggleInputGrabPlat(true);
1556 
1557 		if (effects)
1558 			core->sound->playSfx("Menu-Close");
1559 
1560 		hideInGameMenuExitCheck(false);
1561 		playingSongInMenu = -1;
1562 
1563 
1564 		float t = 0.3;
1565 
1566 		if (!effects)
1567 			t = 0;
1568 		//if (avatar->isEntityDead()) return;
1569 
1570 		int i = 0;
1571 
1572 		for (i = 0; i < foodHolders.size(); i++)
1573 		{
1574 			foodHolders[i]->dropFood();
1575 		}
1576 
1577 		dsq->continuity.lastMenuPage = currentMenuPage;
1578 		if(cancel && (optionsMenu || keyConfigMenu))
1579 			onOptionsCancel();
1580 		else
1581 			toggleOptionsMenu(false);
1582 
1583 		if (!optionsOnly)
1584 		{
1585 			toggleFoodMenu(false);
1586 			toggleTreasureMenu(false);
1587 			togglePetMenu(false);
1588 			toggleMainMenu(false);
1589 			toggleKeyConfigMenu(false);
1590 		}
1591 
1592 		menuIconGlow->alpha = 0;
1593 
1594 		for (i = 0; i < menu.size(); i++)
1595 		{
1596 			menu[i]->alpha = 0;
1597 			//menu[i]->alpha.interpolateTo(0, t*0.5f);
1598 			//menu[i]->scale.interpolateTo(Vector(0, 0), t);
1599 		}
1600 		for (i = 0; i < spellIcons.size(); i++)
1601 			spellIcons[i]->alpha.interpolateTo(0, t);
1602 		for (i = 0; i < songSlots.size(); i++)
1603 			songSlots[i]->alpha.interpolateTo(0, t);
1604 		songBubbles->alpha.interpolateTo(0, t);
1605 
1606 		/*
1607 		menuEXP->alpha.interpolateTo(0, t);
1608 		menuMoney->alpha.interpolateTo(0, t);
1609 		*/
1610 		if (dsq->game->miniMapRender)
1611 			dsq->game->miniMapRender->slide(0);
1612 
1613 		menuDescription->alpha.interpolateTo(0, t);
1614 		menuBg->alpha.interpolateTo(0, t);
1615 		menuBg->scale.interpolateTo(menuBg->scale*0.5f, t);
1616 		menuBg2->alpha.interpolateTo(0, t);
1617 
1618 
1619 
1620 		if (menuSongs)
1621 			menuSongs->alpha.interpolateTo(0, t);
1622 
1623 		if (menu_blackout)
1624 		{
1625 			menu_blackout->alpha.interpolateTo(0, t);
1626 		}
1627 
1628 		if (showRecipe)
1629 		{
1630 			showRecipe->alpha.interpolateTo(0, t);
1631 		}
1632 
1633 		if (effects)
1634 			core->main(t);
1635 
1636 		if (menu_blackout)
1637 		{
1638 			menu_blackout->safeKill();
1639 			menu_blackout = 0;
1640 		}
1641 		if (effects)
1642 			togglePause(false);
1643 		inGameMenu = false;
1644 		//toggleMiniMapRender(1);
1645 
1646 		for (int i = 0; i < songTips.size(); i++)
1647 			songTips[i]->alpha = 0;
1648 
1649 
1650 
1651 
1652 		for (int i = 0; i < dropIngrNames.size(); i++)
1653 		{
1654 			dsq->game->spawnIngredient(dropIngrNames[i], avatar->position + Vector(0,-96), 1, 1);
1655 		}
1656 		dropIngrNames.clear();
1657 
1658 		if (effects)
1659 			dsq->quitNestedMain();
1660 
1661 		dsq->routeShoulder = true;
1662 	}
1663 
1664 	menuBg->setHidden(true);
1665 	opt_save->setHidden(true);
1666 	opt_cancel->setHidden(true);
1667 	options->setHidden(true);
1668 	keyConfigButton->setHidden(true);
1669 	cook->setHidden(true);
1670 	foodSort->setHidden(true);
1671 	recipes->setHidden(true);
1672 	use->setHidden(true);
1673 	prevFood->setHidden(true);
1674 	nextFood->setHidden(true);
1675 	prevTreasure->setHidden(true);
1676 	nextTreasure->setHidden(true);
1677 	circlePageNum->setHidden(true);
1678 	previewRecipe->setHidden(true);
1679 	showRecipe->setHidden(true);
1680 	recipeMenu.scroll->setHidden(true);
1681 	recipeMenu.scrollEnd->setHidden(true);
1682 	recipeMenu.header->setHidden(true);
1683 	recipeMenu.page->setHidden(true);
1684 	recipeMenu.prevPage->setHidden(true);
1685 	recipeMenu.nextPage->setHidden(true);
1686 	menuDescription->setHidden(true);
1687 	eAre->setHidden(true);
1688 	eYes->setHidden(true);
1689 	eNo->setHidden(true);
1690 	menuIconGlow->setHidden(true);
1691 	for (int i = 0; i < menu.size(); i++)
1692 		menu[i]->setHidden(true);
1693 	for (int i = 0; i < treasureSlots.size(); i++)
1694 		treasureSlots[i]->setHidden(true);
1695 	treasureDescription->setHidden(true);
1696 	for (int i = 0; i < foodSlots.size(); i++)
1697 		foodSlots[i]->setHidden(true);
1698 }
1699 
onLeftMouseButton()1700 void Game::onLeftMouseButton()
1701 {
1702 	// hud button
1703 	/*
1704 	if (avatar && !avatar->isCharging())
1705 	{
1706 
1707 		if ((core->mouse.position - Vector(20, 20)).getSquaredLength2D() < sqr(40))
1708 		{
1709 			if (paused)
1710 				hideInGameMenu();
1711 			else
1712 				showInGameMenu();
1713 		}
1714 	}
1715 	*/
1716 }
1717 
1718 /*
1719 void Game::onActivate()
1720 {
1721 	if (!dsq->gui.isInteractionSelectorOpen() && avatar->isInputEnabled())
1722 	{
1723 		Element * e = dsq->getElementAtVector(dsq->cursor->position);
1724 		if (e)
1725 		{
1726 			// open a pop-up menu
1727 			// how?
1728 			// gui system
1729 			// embed menu control in all elements?
1730 				// if in all elements -> stupid, because you can only have on menu at once
1731 			elementWithMenu = e;
1732 			dsq->gui.openInteractionSelectorForElement(e);
1733 		}
1734 	}
1735 
1736 	if (dsq->gui.isInteractionSelectorOpen())
1737 	{
1738 		if (dsq->gui.menu.getSelectedEntry() > -1)
1739 		{
1740 			Interaction::Type type = elementWithMenu->interactions[dsq->gui.menu.getSelectedEntry()].getType();
1741 			dsq->gui.closeInteractionSelector();
1742 			// will crash sometime
1743 			elementWithMenu->interact(type, avatar);
1744 			elementWithMenu = 0;
1745 
1746 
1747 			avatar->enableInput();
1748 			//dsq->gui.menu.clearEntries();
1749 		}
1750 	}
1751 	else if (dsq->gui.isChoiceMenuOpen())
1752 	{
1753 		if (dsq->gui.choiceMenu.getSelectedEntry() > -1)
1754 		{
1755 			selectedChoice = dsq->gui.choiceMenu.getSelectedEntryName();
1756 			dsq->gui.closeChoiceMenu();
1757 			if (core->getNestedMains() > 1)
1758 			{
1759 				core->quitNestedMain();
1760 			}
1761 		}
1762 	}
1763 	else if(core->getNestedMains())
1764 	{
1765 		core->quitNestedMain();
1766 	}
1767 }
1768 */
1769 
spawnManaBall(Vector pos,float a)1770 void Game::spawnManaBall(Vector pos, float a)
1771 {
1772 	ManaBall *m = new ManaBall(pos, a);
1773 	addRenderObject(m, LR_PARTICLES);
1774 }
1775 
refreshItemSlotIcons()1776 void Game::refreshItemSlotIcons()
1777 {
1778 	/*
1779 	for (int i = 0; i < itemSlotIcons.size(); i++)
1780 	{
1781 		if (dsq->continuity.itemSlots[i] != -1)
1782 		{
1783 			itemSlotIcons[i]->setTexture(dsq->getItemTexture(dsq->continuity.itemSlots[i]));
1784 			int n = dsq->continuity.getNumberOf(dsq->continuity.itemSlots[i]);
1785 			if (n > 0)
1786 				itemSlotIcons[i]->alpha = 1;
1787 			else
1788 				itemSlotIcons[i]->alpha = 0;
1789 		}
1790 		else
1791 			itemSlotIcons[i]->alpha = 0;
1792 		itemSlotIcons[i]->setWidthHeight(32, 32);
1793 
1794 
1795 	}
1796 	*/
1797 	/*
1798 	if (n > 0)
1799 		itemSlotIcons[i]->alpha.interpolateTo(1,0.2);
1800 	else
1801 		itemSlotIcons[i]->alpha.interpolateTo(0,0.2);
1802 	*/
1803 }
1804 
clearPointers()1805 void Game::clearPointers()
1806 {
1807 	bg = 0;
1808 	bg2 = 0;
1809 	avatar = 0;
1810 }
1811 
warpPrep()1812 void Game::warpPrep()
1813 {
1814 	avatar->onWarp();
1815 	fromVel = avatar->vel;
1816 	fromVel.setLength2D(10);
1817 	fromPosition = avatar->position;
1818 }
1819 
warpToSceneNode(std::string scene,std::string node)1820 void Game::warpToSceneNode(std::string scene, std::string node)
1821 {
1822 	warpPrep();
1823 
1824 	sceneToLoad = scene;
1825 	toNode = node;
1826 	stringToLower(sceneToLoad);
1827 	stringToLower(toNode);
1828 
1829 	if (avatar->isfh())
1830 		toFlip = 1;
1831 
1832 
1833 	core->enqueueJumpState("Game");
1834 }
1835 
warpToSceneFromNode(Path * p)1836 void Game::warpToSceneFromNode( Path *p)
1837 {
1838 	warpPrep();
1839 
1840 	sceneToLoad = p->warpMap;
1841 
1842 	toNode = "";
1843 	if (!p->warpNode.empty())
1844 	{
1845 		toNode = p->warpNode;
1846 		toFlip = p->toFlip;
1847 		stringToLower(toNode);
1848 	}
1849 	else
1850 	{
1851 		fromScene = sceneName;
1852 		fromWarpType = p->warpType;
1853 	}
1854 
1855 	stringToLower(fromScene);
1856 	stringToLower(sceneToLoad);
1857 
1858 	core->enqueueJumpState("Game");
1859 }
1860 
transitionToScene(std::string scene)1861 void Game::transitionToScene(std::string scene)
1862 {
1863 	if (avatar)
1864 	{
1865 		avatar->onWarp();
1866 	}
1867 	sceneToLoad = scene;
1868 	stringToLower(sceneToLoad);
1869 
1870 	core->enqueueJumpState("Game", false);
1871 }
1872 
getElementTemplateByIdx(int idx)1873 ElementTemplate *Game::getElementTemplateByIdx(int idx)
1874 {
1875 	for (int i = 0; i < elementTemplates.size(); i++)
1876 	{
1877 		if (elementTemplates[i].idx == idx)
1878 		{
1879 			return &elementTemplates[i];
1880 		}
1881 	}
1882 	return 0;
1883 }
1884 
createElement(int idx,Vector position,int bgLayer,RenderObject * copy,ElementTemplate * et)1885 Element* Game::createElement(int idx, Vector position, int bgLayer, RenderObject *copy, ElementTemplate *et)
1886 {
1887 	if (idx == -1) return 0;
1888 
1889 	if (!et)
1890 		et = this->getElementTemplateByIdx(idx);
1891 
1892 	Element *element = new Element();
1893 	if (et)
1894 	{
1895 		element->setTexture(et->gfx);
1896 		element->alpha = et->alpha;
1897 	}
1898 
1899 	element->position = position;
1900 	element->position.z = -0.05;
1901 	element->templateIdx = idx;
1902 
1903 	element->bgLayer = bgLayer;
1904 
1905 	if (et)
1906 	{
1907 		if (et->w != -1 && et->h != -1)
1908 			element->setWidthHeight(et->w, et->h);
1909 	}
1910 	if (et)
1911 	{
1912 		if (et->tu1 != 0 || et->tu2 != 0 || et->tv1 != 0 || et->tv2 != 0)
1913 		{
1914 			element->upperLeftTextureCoordinates = Vector(et->tu1, et->tv1);
1915 			element->lowerRightTextureCoordinates = Vector(et->tu2, et->tv2);
1916 		}
1917 	}
1918 	if (copy)
1919 	{
1920 		element->scale = copy->scale;
1921 		if (copy->isfh())
1922 			element->flipHorizontal();
1923 		if (copy->isfv())
1924 			element->flipVertical();
1925 		element->rotation = copy->rotation;
1926 		Quad *q = dynamic_cast<Quad*>(copy);
1927 		if (q)
1928 		{
1929 			element->repeatTextureToFill(q->isRepeatingTextureToFill());
1930 		}
1931 	}
1932 	addRenderObject(element, LR_ELEMENTS1+bgLayer);
1933 	dsq->addElement(element);
1934 	//element->updateCullVariables();
1935 
1936 	return element;
1937 }
1938 
addObsRow(int tx,int ty,int len)1939 void Game::addObsRow(int tx, int ty, int len)
1940 {
1941 	ObsRow obsRow(tx, ty, len);
1942 	obsRows.push_back(obsRow);
1943 }
1944 
clearObsRows()1945 void Game::clearObsRows()
1946 {
1947 	obsRows.clear();
1948 }
1949 
fillGridFromQuad(Quad * q,ObsType obsType,bool trim)1950 void Game::fillGridFromQuad(Quad *q, ObsType obsType, bool trim)
1951 {
1952 #ifdef BBGE_BUILD_OPENGL
1953 	if (q->texture)
1954 	{
1955 		std::vector<TileVector> obs;
1956 		TileVector tpos(q->position);
1957 		int widthscale = q->getWidth()*q->scale.x;
1958 		int heightscale = q->getHeight()*q->scale.y;
1959 		int w2 = widthscale/2;
1960 		int h2 = heightscale/2;
1961 		w2/=TILE_SIZE;
1962 		h2/=TILE_SIZE;
1963 		tpos.x -= w2;
1964 		tpos.y -= h2;
1965 
1966 		int w = 0, h = 0;
1967 		unsigned int size = 0;
1968 		unsigned char *data = q->texture->getBufferAndSize(&w, &h, &size);
1969 		if (!data)
1970 		{
1971 			debugLog("Failed to get buffer in Game::fillGridFromQuad()");
1972 			return;
1973 		}
1974 
1975 		int szx = TILE_SIZE/q->scale.x;
1976 		int szy = TILE_SIZE/q->scale.y;
1977 		if (szx < 1) szx = 1;
1978 		if (szy < 1) szy = 1;
1979 
1980 		for (int tx = 0; tx < widthscale; tx+=TILE_SIZE)
1981 		{
1982 			for (int ty = 0; ty < heightscale; ty+=TILE_SIZE)
1983 			{
1984 				int num = 0;
1985 				for (int x = 0; x < szx; x++)
1986 				{
1987 					for (int y = 0; y < szy; y++)
1988 					{
1989 						// starting position =
1990 						// tx / scale.x
1991 						unsigned int px = int(tx/q->scale.x) + x;
1992 						unsigned int py = int(ty/q->scale.y) + y;
1993 						if (px < unsigned(w) && py < unsigned(h))
1994 						{
1995 							unsigned int p = (py*unsigned(w)*4) + (px*4) + 3; // position of alpha component
1996 							if (p < size && data[p] >= 254)
1997 							{
1998 								num ++;
1999 							}
2000 							else
2001 							{
2002 								break;
2003 							}
2004 						}
2005 					}
2006 				}
2007 
2008 				if (num >= int((szx*szy)*0.8f))
2009 				//if (num >= int((szx*szy)))
2010 				{
2011 					// add tile
2012 					//dsq->game->setGrid(TileVector(int(tx/TILE_SIZE)+tpos.x, int(ty/TILE_SIZE)+tpos.y), 1);
2013 					obs.push_back(TileVector(int(tx/TILE_SIZE), int(ty/TILE_SIZE)));
2014 				}
2015 			}
2016 		}
2017 
2018 		free(data);
2019 
2020 		if (trim)
2021 		{
2022 			std::vector<TileVector> obsCopy;
2023 			obsCopy.swap(obs);
2024 			// obs now empty
2025 
2026 			int sides = 0;
2027 			for (int i = 0; i < obsCopy.size(); i++)
2028 			{
2029 				sides = 0;
2030 				for (int j = 0; j < obsCopy.size(); j++)
2031 				{
2032 					if (i != j)
2033 					{
2034 						if (
2035 							(obsCopy[j].x == obsCopy[i].x-1 && obsCopy[j].y == obsCopy[i].y)
2036 						||	(obsCopy[j].x == obsCopy[i].x+1 && obsCopy[j].y == obsCopy[i].y)
2037 						||	(obsCopy[j].y == obsCopy[i].y-1 && obsCopy[j].x == obsCopy[i].x)
2038 						||	(obsCopy[j].y == obsCopy[i].y+1 && obsCopy[j].x == obsCopy[i].x)
2039 						)
2040 						{
2041 							sides++;
2042 						}
2043 						if (sides>=4)
2044 						{
2045 							obs.push_back(obsCopy[i]);
2046 							break;
2047 						}
2048 					}
2049 				}
2050 			}
2051 		}
2052 
2053 
2054 		glPushMatrix();
2055 
2056 		for (int i = 0; i < obs.size(); i++)
2057 		{
2058 			glLoadIdentity();
2059 
2060 			glRotatef(q->rotation.z, 0, 0, 1);
2061 			if (q->isfh())
2062 			{
2063 				glRotatef(180, 0, 1, 0);
2064 			}
2065 
2066 			//glTranslatef((obs[i].x-w2)*TILE_SIZE+TILE_SIZE/2, (obs[i].y-h2)*TILE_SIZE + TILE_SIZE/2, 0);
2067 			glTranslatef((obs[i].x-w2), (obs[i].y-h2), 0);
2068 
2069 			float m[16];
2070 			glGetFloatv(GL_MODELVIEW_MATRIX, m);
2071 			float x = m[12];
2072 			float y = m[13];
2073 
2074 			//dsq->game->setGrid(TileVector(tpos.x+(w2*TILE_SIZE)+(x/TILE_SIZE), tpos.y+(h2*TILE_SIZE)+(y/TILE_SIZE)), obsType);
2075 			TileVector tvec(tpos.x+w2+x, tpos.y+h2+y);
2076 			if (!dsq->game->isObstructed(tvec))
2077 				dsq->game->addGrid(tvec, obsType);
2078 
2079 		}
2080 		glPopMatrix();
2081 	}
2082 #endif
2083 }
2084 
getNoteName(int n,const std::string & pre)2085 std::string Game::getNoteName(int n, const std::string &pre)
2086 {
2087 	std::ostringstream os;
2088 	os << pre << "Note" << n;
2089 
2090 	if (n == 6 && bNatural)
2091 	{
2092 		os << "b";
2093 	}
2094 	//debugLog(os.str());
2095 	return os.str();
2096 }
2097 
clearDynamicGrid(unsigned char maskbyte)2098 void Game::clearDynamicGrid(unsigned char maskbyte /* = OT_MASK_BLACK */)
2099 {
2100 	// just to be sure in case the grid/type sizes change,
2101 	// otherwise there is a chance to write a few bytes over the end of the buffer -- FG
2102 	compile_assert(sizeof(grid) % sizeof(uint32) == 0);
2103 
2104 	unsigned char *gridstart = &grid[0][0];
2105 	uint32 *gridend = (uint32*)(gridstart + sizeof(grid));
2106 	uint32 *gridptr = (uint32*)gridstart;
2107 	// mask out specific bytes
2108 	// use full uint32 rounds instead of single-bytes to speed things up.
2109 	const uint32 mask = maskbyte | (maskbyte << 8) | (maskbyte << 16) | (maskbyte << 24);
2110 	do
2111 	{
2112 		*gridptr &= mask;
2113 		++gridptr;
2114 	}
2115 	while(gridptr < gridend);
2116 }
2117 
reconstructEntityGrid()2118 void Game::reconstructEntityGrid()
2119 {
2120 	clearDynamicGrid(~OT_INVISIBLEENT);
2121 
2122 	FOR_ENTITIES(i)
2123 	{
2124 		Entity *e = *i;
2125 		e->fillGrid();
2126 	}
2127 }
2128 
reconstructGrid(bool force)2129 void Game::reconstructGrid(bool force)
2130 {
2131 	if (!force && isSceneEditorActive()) return;
2132 
2133 	clearGrid();
2134 	int i = 0;
2135 	for (i = 0; i < dsq->getNumElements(); i++)
2136 	{
2137 		Element *e = dsq->getElement(i);
2138 		e->fillGrid();
2139 	}
2140 
2141 	ObsRow *o;
2142 	for (i = 0; i < obsRows.size(); i++)
2143 	{
2144 		o = &obsRows[i];
2145 		for (int tx = 0; tx < o->len; tx++)
2146 		{
2147 			setGrid(TileVector(o->tx + tx, o->ty), OT_BLACK);
2148 		}
2149 	}
2150 
2151 	FOR_ENTITIES(i)
2152 	{
2153 		Entity *e = *i;
2154 		e->fillGrid();
2155 	}
2156 
2157 	trimGrid();
2158 }
2159 
trimGrid()2160 void Game::trimGrid()
2161 {
2162 	// Prevent the left- and rightmost column of black tiles
2163 	// from beeing drawn. (The maps were designed with this mind...)
2164 	for (int x = 0; x < MAX_GRID; x++)
2165 	{
2166 		const unsigned char *curCol   = grid[x]; // safe
2167 		const unsigned char *leftCol  = dsq->game->getGridColumn(x-1); // unsafe
2168 		const unsigned char *rightCol = dsq->game->getGridColumn(x+1); // unsafe
2169 		for (int y = 0; y < MAX_GRID; y++)
2170 		{
2171 			if (curCol[y] & OT_MASK_BLACK)
2172 			{
2173 				if (!(leftCol[y] & OT_MASK_BLACK) || !(rightCol[y] & OT_MASK_BLACK))
2174 					setGrid(TileVector(x, y), OT_BLACKINVIS);
2175 			}
2176 		}
2177 	}
2178 }
2179 
dilateGrid(unsigned int radius,ObsType test,ObsType set,ObsType allowOverwrite)2180 void Game::dilateGrid(unsigned int radius, ObsType test, ObsType set, ObsType allowOverwrite)
2181 {
2182 	if(!radius)
2183 		return;
2184 	const int lim = MAX_GRID - radius;
2185 	const unsigned int denyOverwrite = ~allowOverwrite;
2186 	// Box dilation is separable, so we do a two-pass by axis
2187 	int dilate = 0;
2188 
2189 	// dilate rows
2190 	for (int y = 0; y < MAX_GRID; ++y)
2191 	{
2192 		for (int x = radius; x < lim; ++x)
2193 		{
2194 			if (grid[x][y] & test)
2195 			{
2196 				dilate = 2 * radius;
2197 				goto doDilate1;
2198 			}
2199 			if(dilate)
2200 			{
2201 				--dilate;
2202 				doDilate1:
2203 				if((grid[x - radius][y] & denyOverwrite) == OT_EMPTY)
2204 					grid[x - radius][y] |= set;
2205 			}
2206 		}
2207 		assert(lim + dilate < MAX_GRID);
2208 		for(int x = 0; x < dilate; ++x)
2209 			if(!(grid[x][y - radius] & test))
2210 				grid[x][y - radius] |= set;
2211 	}
2212 
2213 	// dilate colums
2214 	dilate = 0;
2215 	for (int x = 0; x < MAX_GRID; ++x)
2216 	{
2217 		unsigned char * const curCol = grid[x];
2218 		for (int y = radius; y < lim; ++y)
2219 		{
2220 			if (curCol[y] & test)
2221 			{
2222 				dilate = 2 * radius;
2223 				goto doDilate2;
2224 			}
2225 			if(dilate)
2226 			{
2227 				--dilate;
2228 				doDilate2:
2229 				if((curCol[y - radius] & denyOverwrite) == OT_EMPTY)
2230 					curCol[y - radius] |= set;
2231 			}
2232 		}
2233 		assert(lim + dilate < MAX_GRID);
2234 		for(int y = 0; y < dilate; ++y)
2235 			if(!(curCol[y - radius] & test))
2236 				curCol[y - radius] |= set;
2237 	}
2238 }
2239 
getCoverage(Vector pos,int sampleArea)2240 float Game::getCoverage(Vector pos, int sampleArea)
2241 {
2242 	TileVector t(pos);
2243 	int total = 0, covered = 0;
2244 	for (int x = t.x-sampleArea; x <= t.x+sampleArea; x++)
2245 	{
2246 		for (int y = t.y-sampleArea; y <= t.y+sampleArea; y++)
2247 		{
2248 			if (x == t.x && y == t.y) continue;
2249 			TileVector ct(x,y);
2250 			Vector vt = ct.worldVector();
2251 			if (isObstructed(ct))
2252 			{
2253 				covered++;
2254 			}
2255 			total++;
2256 		}
2257 	}
2258 	return float(covered)/float(total);
2259 }
2260 
getPercObsInArea(Vector pos,int sampleArea,int obs)2261 float Game::getPercObsInArea(Vector pos, int sampleArea, int obs)
2262 {
2263 	int sz = sampleArea * sampleArea;
2264 	int c = 0;
2265 	TileVector t(pos);
2266 
2267 	for (int x = t.x-sampleArea; x <= t.x+sampleArea; x++)
2268 	{
2269 		for (int y = t.y-sampleArea; y <= t.y+sampleArea; y++)
2270 		{
2271 			if (isObstructed(TileVector(x, y), obs))
2272 			{
2273 				c++;
2274 			}
2275 		}
2276 	}
2277 	return float(c)/float(sz);
2278 }
2279 
getWallNormal(Vector pos,int sampleArea,float * dist,int obs)2280 Vector Game::getWallNormal(Vector pos, int sampleArea, float *dist, int obs)
2281 {
2282 	TileVector t(pos);
2283 	//Vector p = t.worldVector();
2284 	Vector avg;
2285 	int c = 0;
2286 	//float maxLen = -1;
2287 	std::vector<Vector> vs;
2288 	if (dist != NULL)
2289 		*dist = -1;
2290 	for (int x = t.x-sampleArea; x <= t.x+sampleArea; x++)
2291 	{
2292 		for (int y = t.y-sampleArea; y <= t.y+sampleArea; y++)
2293 		{
2294 			if (x == t.x && y == t.y) continue;
2295 			TileVector ct(x,y);
2296 			Vector vt = ct.worldVector();
2297 			if (isObstructed(ct, obs))
2298 			{
2299 				/*
2300 				int xDiff = abs(t.x - x);
2301 				int yDiff = abs(t.y - y);
2302 				float xv = float(sampleArea-xDiff)/float(sampleArea);
2303 				if (x < t.x)
2304 					xv = -xv;
2305 				float yv = float(sampleArea-yDiff)/float(sampleArea);
2306 				if (y < t.y)
2307 					yv = -yv;
2308 				Vector v(-xv, -yv);
2309 				*/
2310 				/*
2311 				int xDiff = t.x-x;
2312 				int yDiff = t.y-y;
2313 				*/
2314 
2315 				int xDiff = pos.x-vt.x;
2316 				int yDiff = pos.y-vt.y;
2317 				/*
2318 				float xEffect = (sampleArea*TILE_SIZE - abs(xDiff))*1.0f;
2319 				float yEffect = (sampleArea*TILE_SIZE - abs(yDiff))*1.0f;
2320 				*/
2321 				//Vector v(xDiff*xEffect, yDiff*yEffect);
2322 				Vector v(xDiff, yDiff);
2323 				vs.push_back (v);
2324 
2325 				if (dist!=NULL)
2326 				{
2327 					float d = (vt-pos).getLength2D();
2328 					if (*dist == -1 || d < *dist)
2329 					{
2330 						*dist = d;
2331 					}
2332 				}
2333 				/*
2334 				float len = v.getLength2D();
2335 				if (len > maxLen || maxLen == -1)
2336 					maxLen = len;
2337 				*/
2338 				//Vector v(xDiff, yDiff);
2339 				//avg += v;
2340 				//c++;
2341 			}
2342 		}
2343 	}
2344 	int sz = (TILE_SIZE*(sampleArea-1));
2345 	for (int i = 0; i < vs.size(); i++)
2346 	{
2347 		float len = vs[i].getLength2D();
2348 		if (len < sz)
2349 		{
2350 			vs[i].setLength2D(sz - len);
2351 			c++;
2352 			avg += vs[i];
2353 		}
2354 	}
2355 	if (c)
2356 	{
2357 		avg /= c;
2358 		if (avg.x != 0 || avg.y != 0)
2359 		{
2360 			avg.normalize2D();
2361 			avg.z = 0;
2362 		}
2363 	}
2364 	else
2365 	{
2366 		avg.x = avg.y = 0;
2367 	}
2368 
2369 	/*
2370 	avg.x = -avg.x;
2371 	avg.y = -avg.y;
2372 	*/
2373 	return avg;
2374 }
2375 
getEntityAtCursor()2376 Entity *Game::getEntityAtCursor()
2377 {
2378 	int minDist = -1;
2379 	Entity *selected = 0;
2380 	FOR_ENTITIES(i)
2381 	{
2382 		Entity *e = *i;
2383 		int dist = (e->position - dsq->getGameCursorPosition()).getSquaredLength2D();
2384 		if (dist < sqr(64) && (minDist == -1 || dist < minDist))
2385 		{
2386 			selected = e;
2387 			dist = minDist;
2388 		}
2389 	}
2390 	return selected;
2391 }
2392 
2393 // WARNING: will remove from save file, if present!
removeEntityAtCursor()2394 bool Game::removeEntityAtCursor()
2395 {
2396 	Entity *selected = getEntityAtCursor();
2397 	if (selected)
2398 	{
2399 		return removeEntity(selected);
2400 	}
2401 	return false;
2402 }
2403 
removeEntity(Entity * selected)2404 bool Game::removeEntity(Entity *selected)
2405 {
2406 	selected->setState(Entity::STATE_DEAD);
2407 	selected->safeKill();
2408 	XMLElement *e = this->saveFile->FirstChildElement("Enemy");
2409 	while (e)
2410 	{
2411 		int x = atoi(e->Attribute("x"));
2412 		int y = atoi(e->Attribute("y"));
2413 		if (int(selected->startPos.x) == x && int(selected->startPos.y) == y)
2414 		{
2415 			this->saveFile->DeleteChild(e);
2416 			//delete e;
2417 			return true;
2418 		}
2419 
2420 		e = e->NextSiblingElement("Enemy");
2421 	}
2422 
2423 	for (int i = 0; i < entitySaveData.size(); i++)
2424 	{
2425 		if (entitySaveData[i].x == int(selected->startPos.x) && entitySaveData[i].y == int(selected->startPos.y))
2426 		{
2427 			std::vector<EntitySaveData> copy = entitySaveData;
2428 			entitySaveData.clear();
2429 			for (int j = 0; j < copy.size(); j++)
2430 			{
2431 				if (j != i)
2432 					entitySaveData.push_back(copy[j]);
2433 			}
2434 			return true;
2435 		}
2436 	}
2437 	return false;
2438 }
2439 
removeIngredient(Ingredient * i)2440 void Game::removeIngredient(Ingredient *i)
2441 {
2442 	ingredients.remove(i);
2443 }
2444 
bindIngredients()2445 void Game::bindIngredients()
2446 {
2447 	for (Ingredients::iterator i = ingredients.begin(); i != ingredients.end(); ++ i)
2448 	{
2449 		Vector v = avatar->position - (*i)->position;
2450 		if (!v.isLength2DIn(16))
2451 		{
2452 			v.setLength2D(500);
2453 			(*i)->vel += v;
2454 		}
2455 	}
2456 }
2457 
2458 /*
2459 void Game::getEntityTypeName(int entityType)
2460 {
2461 	switch(entityType)
2462 	{
2463 	case ET_NAUTILUS:		return "Nautilus";
2464 	case ET_CENTIPEDE:		return "Centipede";
2465 	case ET_WATERBUG:		return "WaterBug";
2466 	case ET_CRAWLER:		return "Crawler";
2467 	case ET_HELLBEASTHEAD:	return "HellBeastHead";
2468 	case ET_SPINNER:		return "Spinner";
2469 	case ET_SQUID:			return "Squid";
2470 	case ET_JELLYFISH:		return "JellyFish";
2471 	case ET_ROCKHEAD:		return "RockHead";
2472 	case ET_SPIKE:			return "Spike";
2473 	case ET_MEGASHRIMP:		return "MegaShrimp";
2474 	case ET_ZUNNA:			return "Zunna";
2475 	case ET_PICKUPITEM:		return "PickupItem";
2476 	case ET_HERETICSKULL:	return "HereticSkull";
2477 	case ET_RATTLEOYSTER:	return "RattleOyster";
2478 	case ET_LEACH:			return "Leach";
2479 	case ET_QUEENHYDRA:		return "QueenHydra";
2480 	case ET_HYDRALARVA:		return "Lumite";
2481 	case ET_BARRIER:		return "Barrier";
2482 	}
2483 }
2484 */
2485 
loadEntityTypeList()2486 void Game::loadEntityTypeList()
2487 // and group list!
2488 {
2489 	entityTypeList.clear();
2490 	InStream in("scripts/entities/entities.txt");
2491 	std::string line;
2492 	if(!in)
2493 	{
2494 		exit_error(dsq->continuity.stringBank.get(2008).c_str());
2495 	}
2496 	while (std::getline(in, line))
2497 	{
2498 		std::string name, prevGfx;
2499 		int idx;
2500 		float scale;
2501 		std::istringstream is(line);
2502 		is >> idx >> name >> prevGfx >> scale;
2503 		//errorLog(line);
2504 		/*
2505 		std::ostringstream os;
2506 		os << "adding entity [" << name << "] idx[" << idx << "] prevGfx [" << prevGfx << "] scale [" << scale << "]";
2507 		debugLog(os.str());
2508 		*/
2509 		entityTypeList.push_back(EntityClass(name, 1, idx, prevGfx, scale));
2510 	}
2511 	in.close();
2512 
2513 #ifdef AQUARIA_BUILD_SCENEEDITOR
2514 	entityGroups.clear();
2515 
2516 	std::string fn = "scripts/entities/entitygroups.txt";
2517 	if (dsq->mod.isActive())
2518 	{
2519 		fn = dsq->mod.getPath() + "entitygroups.txt";
2520 	}
2521 
2522 	InStream in2(fn.c_str());
2523 
2524 	int curGroup=0;
2525 	while (std::getline(in2, line))
2526 	{
2527 		if (line.find("GROUP:")!=std::string::npos)
2528 		{
2529 			line = line.substr(6, line.size());
2530 			//debugLog("****** NEWGROUP: " + line);
2531 			EntityGroup newGroup;
2532 			newGroup.name = line;
2533 			//entityGroups[line] = newGroup;
2534 			//
2535 			entityGroups.push_back(newGroup);
2536 			curGroup = entityGroups.size()-1;
2537         }
2538 		else if (!line.empty())
2539 		{
2540 			EntityGroupEntity ent;
2541 			std::istringstream is(line);
2542 			std::string addLine, graphic;
2543 			is >> ent.name >> ent.gfx;
2544 			stringToLower(ent.name);
2545 			//debugLog("**adding: " + addLine);
2546 			entityGroups[curGroup].entities.push_back(ent);
2547 		}
2548 	}
2549 	in2.close();
2550 
2551 	game->sceneEditor.entityPageNum = 0;
2552 	//game->sceneEditor.page = entityGroups.begin();
2553 #endif
2554 }
2555 
getEntityClassForEntityType(const std::string & type)2556 EntityClass *Game::getEntityClassForEntityType(const std::string &type)
2557 {
2558 	for (int i = 0; i < entityTypeList.size(); i++)
2559 	{
2560 	/*
2561 		std::ostringstream os;
2562 		os << "Comparing entityTypeList [" << entityTypeList[i].name << "] with type [" << type << "]";
2563 		debugLog(os.str());
2564 		*/
2565 		if (nocasecmp(entityTypeList[i].name, type)==0)
2566 			return &entityTypeList[i];
2567 	}
2568 	return 0;
2569 }
2570 
getIdxForEntityType(std::string type)2571 int Game::getIdxForEntityType(std::string type)
2572 {
2573 	//if (!type.empty() && type[0] == '@')	return -1;
2574 
2575 	for (int i = 0; i < entityTypeList.size(); i++)
2576 	{
2577 		if (nocasecmp(entityTypeList[i].name, type)==0)
2578 			return entityTypeList[i].idx;
2579 	}
2580 	return -1;
2581 }
2582 
createEntity(int idx,int id,Vector position,int rot,bool createSaveData,std::string name,EntityType et,bool doPostInit)2583 Entity *Game::createEntity(int idx, int id, Vector position, int rot, bool createSaveData, std::string name, EntityType et, bool doPostInit)
2584 {
2585 	std::string type;
2586 	for (int i = 0; i < dsq->game->entityTypeList.size(); i++)
2587 	{
2588 		EntityClass *ec = &dsq->game->entityTypeList[i];
2589 		if (ec->idx == idx)
2590 		{
2591 			type = ec->name;
2592 			return createEntity(type, id, position, rot, createSaveData, name, et, doPostInit);
2593 		}
2594 	}
2595 	return 0;
2596 }
2597 
2598 // ensure a limit of entity types in the current level
2599 // older entities with be culled if state is set to 0
2600 // otherwise, the older entities will have the state set
ensureLimit(Entity * e,int num,int state)2601 void Game::ensureLimit(Entity *e, int num, int state)
2602 {
2603 	int idx = e->entityTypeIdx;
2604 	int c = 0;
2605 	std::list<Entity*> entityList;
2606 	FOR_ENTITIES(i)
2607 	{
2608 		if ((*i)->entityTypeIdx == idx && (state == 0 || (*i)->getState() != state))
2609 		{
2610 			entityList.push_back(*i);
2611 			c++;
2612 		}
2613 	}
2614 
2615 	int numDelete = c-(num+1);
2616 	if (numDelete >= 0)
2617 	{
2618 		for (std::list<Entity*>::iterator i = entityList.begin(); i != entityList.end(); i++)
2619 		{
2620 			if (state == 0)
2621 				(*i)->safeKill();
2622 			else
2623 				(*i)->setState(state);
2624 			numDelete--;
2625 			if (numDelete <= 0)
2626 				break;
2627 		}
2628 	}
2629 }
2630 
establishEntity(Entity * e,int id,Vector position,int rot,bool createSaveData,std::string name,EntityType et,bool doPostInit)2631 Entity* Game::establishEntity(Entity *e, int id, Vector position, int rot, bool createSaveData, std::string name, EntityType et, bool doPostInit)
2632 {
2633 	// e->layer must be set BEFORE calling this function!
2634 
2635 	std::string type = e->name;
2636 	stringToLower(type);
2637 
2638 
2639 
2640 	// i'm thinking this *should* hold up for new files
2641 	// it will mess up if you're importing an old file
2642 	// the logic being that you're not going to load in an non-ID-specified entity in new files
2643 	// so assignUniqueID should never be called
2644 	// so what i'm going to do is have it bitch
2645 
2646 	// note that when not loading a scene, it is valid to call assignUniqueID here
2647 	if (id != 0)
2648 	{
2649 		e->setID(id);
2650 	}
2651 	else
2652 	{
2653 		if (loadingScene)
2654 		{
2655 			std::ostringstream os;
2656 			os << "ERROR: Assigning Unique ID to a loaded Entity... if this is called from loadScene then Entity IDs may be invalid";
2657 			os << "\nEntityName: " << e->name;
2658 			errorLog(os.str());
2659 		}
2660 		else
2661 		{
2662 			e->assignUniqueID();
2663 		}
2664 	}
2665 
2666 	// NOTE: init cannot be called after "addRenderObject" for some unknown reason
2667 	e->init();
2668 
2669 	Vector usePos = position;
2670 	e->startPos = usePos;
2671 	if (!name.empty())
2672 		e->name = name;
2673 
2674 	e->rotation.z = rot;
2675 
2676 	int idx = getIdxForEntityType(type);
2677 	e->entityTypeIdx = idx;
2678 
2679 
2680 	if (createSaveData)
2681 	{
2682 		int idx = dsq->game->getIdxForEntityType(type);
2683 		entitySaveData.push_back(EntitySaveData(e, idx, usePos.x, usePos.y, rot, e->getID(), e->name));
2684 	}
2685 
2686 	addRenderObject(e, e->layer);
2687 
2688 	if (doPostInit)
2689 	{
2690 		e->postInit();
2691 	}
2692 
2693 	return e;
2694 }
2695 
createEntity(const std::string & t,int id,Vector position,int rot,bool createSaveData,std::string name,EntityType et,bool doPostInit)2696 Entity *Game::createEntity(const std::string &t, int id, Vector position, int rot, bool createSaveData, std::string name, EntityType et, bool doPostInit)
2697 {
2698 	std::string type = t;
2699 	stringToLower(type);
2700 
2701 	ScriptedEntity *e;
2702 
2703 	e = new ScriptedEntity(type, position, et);
2704 
2705 
2706 	return establishEntity(e, id, position, rot, createSaveData, name, et, doPostInit);
2707 }
2708 
initEntities()2709 void Game::initEntities()
2710 {
2711 	FOR_ENTITIES(i)
2712 	{
2713 		Entity *e = *i;
2714 		if (e)
2715 		{
2716 			e->init();
2717 		}
2718 	}
2719 }
2720 
assignEntitiesUniqueIDs()2721 void Game::assignEntitiesUniqueIDs()
2722 {
2723 	FOR_ENTITIES(i)
2724 	{
2725 		Entity *e = *i;
2726 		if (e && e->entityID == 0)
2727 		{
2728 			e->assignUniqueID();
2729 		}
2730 	}
2731 
2732 }
2733 
getEntitySaveDataForEntity(Entity * e,Vector pos)2734 EntitySaveData *Game::getEntitySaveDataForEntity(Entity *e, Vector pos)
2735 {
2736 
2737 	for (int i = 0; i < entitySaveData.size(); i++)
2738 	{
2739 		if (entitySaveData[i].e == e)
2740 		{
2741 			return &entitySaveData[i];
2742 		}
2743 		/*
2744 		if (entitySaveData[i].x == int(e->startPos.x) && entitySaveData[i].y == int(e->startPos.y))
2745 		{
2746 			if (entitySaveData[i].idx == e->entityTypeIdx)
2747 			{
2748 				debugLog("found entity");
2749 				return &entitySaveData[i];
2750 			}
2751 		}
2752 		*/
2753 	}
2754 	return 0;
2755 }
2756 
setTimerTextAlpha(float a,float t)2757 void Game::setTimerTextAlpha(float a, float t)
2758 {
2759 	timerText->alpha.interpolateTo(a, t);
2760 }
2761 
setTimerText(float time)2762 void Game::setTimerText(float time)
2763 {
2764 	std::ostringstream os;
2765 	int mins = int(time/60);
2766 	int secs = time - (mins*60);
2767 	os << mins;
2768 	if (getTimer() > 0.5f)
2769 		os << ":";
2770 	else
2771 		os << ".";
2772 	if (secs < 10)
2773 		os << "0";
2774 	os << secs;
2775 	timerText->setText(os.str());
2776 }
2777 
generateCollisionMask(Quad * q,float overrideCollideRadius)2778 void Game::generateCollisionMask(Quad *q, float overrideCollideRadius /* = 0 */)
2779 {
2780 #ifdef BBGE_BUILD_OPENGL
2781 	if (q->texture)
2782 	{
2783 		q->collidePosition = Vector(0,0,0);
2784 		if (overrideCollideRadius)
2785 			q->collideRadius = overrideCollideRadius;
2786 		else
2787 			q->collideRadius = TILE_SIZE/2;
2788 		q->collisionMask.clear();
2789 		TileVector tpos(q->position);
2790 		int widthscale = q->getWidth()*q->scale.x;
2791 		int heightscale = q->getHeight()*q->scale.y;
2792 		int w2 = widthscale/2;
2793 		int h2 = heightscale/2;
2794 		w2/=TILE_SIZE;
2795 		h2/=TILE_SIZE;
2796 		tpos.x -= w2;
2797 		tpos.y -= h2;
2798 
2799 		int w = 0, h = 0;
2800 		unsigned int size = 0;
2801 		unsigned char *data = q->texture->getBufferAndSize(&w, &h, &size);
2802 		if (!data)
2803 		{
2804 			debugLog("Failed to get buffer in Game::generateCollisionMask()");
2805 			return;
2806 		}
2807 
2808 		q->collisionMaskRadius = 0;
2809 
2810 		Vector collisionMaskHalfVector = Vector(q->getWidth()/2, q->getHeight()/2);
2811 
2812 		int szx = TILE_SIZE/q->scale.x;
2813 		int szy = TILE_SIZE/q->scale.y;
2814 		if (szx < 1) szx = 1;
2815 		if (szy < 1) szy = 1;
2816 
2817 		for (int tx = 0; tx < widthscale; tx+=TILE_SIZE)
2818 		{
2819 			for (int ty = 0; ty < heightscale; ty+=TILE_SIZE)
2820 			{
2821 				int num = 0;
2822 
2823 				for (int x = 0; x < szx; x++)
2824 				{
2825 					for (int y = 0; y < szy; y++)
2826 					{
2827 						// starting position =
2828 						// tx / scale.x
2829 						unsigned int px = int(tx/q->scale.x) + x;
2830 						unsigned int py = int(ty/q->scale.y) + y;
2831 						if (px < unsigned(w) && py < unsigned(h))
2832 						{
2833 							unsigned int p = (py*unsigned(w)*4) + (px*4) + 3; // position of alpha component
2834 							if (p < size && data[p] >= 250)
2835 							{
2836 								num ++;
2837 							}
2838 						}
2839 					}
2840 				}
2841 				if (num >= int((szx*szy)*0.25f))
2842 				{
2843 					TileVector tile(int((tx+TILE_SIZE/2)/TILE_SIZE), int((ty+TILE_SIZE/2)/TILE_SIZE));
2844 					// + Vector(0,TILE_SIZE)
2845 					q->collisionMask.push_back(tile.worldVector() - collisionMaskHalfVector);
2846 				}
2847 			}
2848 		}
2849 
2850 		q->collisionMaskRadius = 512;
2851 
2852 		free(data);
2853 
2854 
2855 		/*
2856 		for (int i = 0; i < q->collisionMask.size(); i++)
2857 		{
2858 			float xsz = q->collisionMask[i].x;
2859 			float ysz = q->collisionMask[i].y;
2860 			if (xsz < 0)	xsz = -xsz;
2861 			if (ysz < 0)	ysz = -ysz;
2862 			if (xsz > q->collisionMaskRadius)
2863 				q->collisionMaskRadius = xsz;
2864 			if (ysz > q->collisionMaskRadius)
2865 				q->collisionMaskRadius = ysz;
2866 		}
2867 		q->collisionMaskRadius += TILE_SIZE/2;
2868 		*/
2869 		/*
2870 		if (w2 > h2)
2871 			q->collisionMaskRadius = w2*2;
2872 		else
2873 			q->collisionMaskRadius = h2*2;
2874 		*/
2875 		//q->collisionMaskRadius = sqrtf(sqr(w2)+sqr(h2));
2876 
2877 		/*
2878 		int rot = rotation.z;
2879 		while (rot > 360)
2880 			rot -= 360;
2881 		while (rot < 0)
2882 			rot += 360;
2883 		*/
2884 	}
2885 #endif
2886 }
2887 
addPath(Path * p)2888 void Game::addPath(Path *p)
2889 {
2890 	paths.push_back(p);
2891 	if (p->pathType >= 0 && p->pathType < PATH_MAX)
2892 	{
2893 		p->nextOfType = firstPathOfType[p->pathType];
2894 		firstPathOfType[p->pathType] = p;
2895 	}
2896 }
2897 
removePath(int idx)2898 void Game::removePath(int idx)
2899 {
2900 	if (idx >= 0 && idx < paths.size()) paths[idx]->destroy();
2901 	std::vector<Path*> copy = this->paths;
2902 	clearPaths();
2903 	for (int i = 0; i < copy.size(); i++)
2904 	{
2905 		if (i != idx)
2906 			addPath(copy[i]);
2907 	}
2908 }
2909 
clearPaths()2910 void Game::clearPaths()
2911 {
2912 	paths.clear();
2913 	for (int i = 0; i < PATH_MAX; i++)
2914 		firstPathOfType[i] = 0;
2915 }
2916 
getIndexOfPath(Path * p)2917 int Game::getIndexOfPath(Path *p)
2918 {
2919 	for (int i = 0; i < paths.size(); i++)
2920 	{
2921 		if (paths[i] == p)
2922 			return i;
2923 	}
2924 	return -1;
2925 }
2926 
getPathAtCursor()2927 Path *Game::getPathAtCursor()
2928 {
2929 	return getNearestPath(dsq->getGameCursorPosition(), "");
2930 	/*
2931 	int range = 128;
2932 	int sz = paths.size();
2933 	for (int i = 0; i < sz; i++)
2934 	{
2935 		Path *p = &(paths[i]);
2936 		if (!p->nodes.empty())
2937 		{
2938 			int dist = (p->nodes[0].position - dsq->getGameCursorPosition()).getSquaredLength2D();
2939 			if (dist < sqr(range))
2940 			{
2941 				return p;
2942 			}
2943 		}
2944 	}
2945 	return 0;
2946 	*/
2947 }
2948 
getScriptedPathAtCursor(bool withAct)2949 Path *Game::getScriptedPathAtCursor(bool withAct)
2950 {
2951 	//int range = 64;
2952 	int sz = paths.size();
2953 	for (int i = 0; i < sz; i++)
2954 	{
2955 		Path *p = (paths[i]);
2956 		if (!p->nodes.empty() && p->hasScript())
2957 		{
2958 			if (!withAct || p->cursorActivation)
2959 			{
2960 				if (p->isCoordinateInside(dsq->getGameCursorPosition()))
2961 				{
2962 					return p;
2963 				}
2964 			}
2965 			/*
2966 			int dist = (p->nodes[0].position - dsq->getGameCursorPosition()).getSquaredLength2D();
2967 			if (dist < sqr(range))
2968 			{
2969 				return p;
2970 			}
2971 			*/
2972 		}
2973 	}
2974 	return 0;
2975 }
2976 
getNearestPath(const Vector & pos,const std::string & s,const Path * ignore)2977 Path *Game::getNearestPath(const Vector &pos, const std::string &s, const Path *ignore)
2978 {
2979 	Path *closest = 0;
2980 	float smallestDist = HUGE_VALF;
2981 	std::string st = s;
2982 	stringToLower(st);
2983 	for (int i = 0; i < dsq->game->paths.size(); i++)
2984 	{
2985 		Path *cp = dsq->game->paths[i];
2986 		if (cp != ignore && !cp->nodes.empty() && (st.empty() || st == cp->label))
2987 		{
2988 			const Vector v = cp->nodes[0].position - pos;
2989 			const float dist = v.getSquaredLength2D();
2990 			if (dist < smallestDist)
2991 			{
2992 				smallestDist = dist;
2993 				closest = cp;
2994 			}
2995 		}
2996 	}
2997 	return closest;
2998 }
2999 
getNearestPath(const Vector & pos,PathType pathType)3000 Path *Game::getNearestPath(const Vector &pos, PathType pathType)
3001 {
3002 	Path *closest = 0;
3003 	float smallestDist = HUGE_VALF;
3004 	for (Path *cp = dsq->game->getFirstPathOfType(pathType); cp; cp = cp->nextOfType)
3005 	{
3006 		if (!cp->nodes.empty())
3007 		{
3008 			const Vector v = cp->nodes[0].position - pos;
3009 			const float dist = v.getSquaredLength2D();
3010 			if (dist < smallestDist)
3011 			{
3012 				smallestDist = dist;
3013 				closest = cp;
3014 			}
3015 		}
3016 	}
3017 	return closest;
3018 }
3019 
getNearestPath(Path * p,std::string s)3020 Path *Game::getNearestPath(Path *p, std::string s)
3021 {
3022 	if (p->nodes.empty()) return 0;
3023 
3024 	return getNearestPath(p->nodes[0].position, s);
3025 }
3026 
getPathByName(std::string name)3027 Path *Game::getPathByName(std::string name)
3028 {
3029 	stringToLowerUserData(name);
3030 	for (int i = 0; i < paths.size(); i++)
3031 	{
3032 		if (paths[i]->label == name)
3033 			return paths[i];
3034 	}
3035 	return 0;
3036 }
3037 
3038 
addKeyConfigLine(RenderObject * group,const std::string & label,const std::string & actionInputName,int y,int l1,int l2,int l3)3039 void Game::addKeyConfigLine(RenderObject *group, const std::string &label, const std::string &actionInputName, int y, int l1, int l2, int l3)
3040 {
3041 	//DebugFont *lb = new DebugFont(6, label);
3042 	TTFText *lb = new TTFText(&dsq->fontArialSmallest);
3043 	lb->setText(label);
3044 	lb->position = Vector(140,y);
3045 	group->addChild(lb, PM_POINTER);
3046 
3047 	AquariaKeyConfig *k1 = new AquariaKeyConfig(actionInputName, INPUTSET_KEY, 0);
3048 	k1->position = Vector(350,y);
3049 	k1->setLock(l1);
3050 	group->addChild(k1, PM_POINTER);
3051 
3052 	AquariaKeyConfig *k2 = new AquariaKeyConfig(actionInputName, INPUTSET_KEY, 1);
3053 	k2->position = Vector(475,y);
3054 	k2->setLock(l2);
3055 	group->addChild(k2, PM_POINTER);
3056 
3057 	AquariaKeyConfig *j1 = new AquariaKeyConfig(actionInputName, INPUTSET_JOY, 0);
3058 	j1->position = Vector(600,y);
3059 	j1->setLock(l3);
3060 	group->addChild(j1, PM_POINTER);
3061 
3062 	k1->setDirMove(DIR_RIGHT, k2);
3063 	k2->setDirMove(DIR_RIGHT, j1);
3064 
3065 	j1->setDirMove(DIR_LEFT, k2);
3066 	k2->setDirMove(DIR_LEFT, k1);
3067 }
3068 
addAxesConfigLine(RenderObject * group,const std::string & label,const std::string & actionInputName,int y,int offx)3069 AquariaKeyConfig *Game::addAxesConfigLine(RenderObject *group, const std::string &label, const std::string &actionInputName, int y, int offx)
3070 {
3071 	/// DebugFont *lb = new DebugFont(6, label);
3072 	TTFText *lb = new TTFText(&dsq->fontArialSmallest);
3073 	lb->setText(label);
3074 	lb->position = Vector(140+offx, y);
3075 	group->addChild(lb, PM_POINTER);
3076 
3077 	AquariaKeyConfig *i1 = new AquariaKeyConfig(actionInputName, INPUTSET_OTHER, 0);
3078 	i1->position = Vector(140+80+offx,y);
3079 	//i1->setLock(l1);
3080 	group->addChild(i1, PM_POINTER);
3081 
3082 	i1->setDirMove(DIR_RIGHT, 0);
3083 	i1->setDirMove(DIR_LEFT, 0);
3084 
3085 	return i1;
3086 }
3087 
doFlagCheck(const std::string & flagCheck,FlagCheckType type,bool lastTruth)3088 bool Game::doFlagCheck(const std::string &flagCheck, FlagCheckType type, bool lastTruth)
3089 {
3090 	if (!flagCheck.empty())
3091 	{
3092 		std::string flagName, comparison, next;
3093 		int value=0;
3094 		std::istringstream is(flagCheck);
3095 		is >> flagName >> comparison >> value >> next;
3096 
3097 		bool truth=false;
3098 		if (comparison == "==")
3099 		{
3100 			if (dsq->continuity.getFlag(flagName) == value) truth = true;
3101 		}
3102 		else if (comparison == "<")
3103 		{
3104 			if (dsq->continuity.getFlag(flagName) < value)	truth = true;
3105 		}
3106 		else if (comparison == ">")
3107 		{
3108 			if (dsq->continuity.getFlag(flagName) > value)	truth = true;
3109 		}
3110 		else if (comparison == "<=")
3111 		{
3112 			if (dsq->continuity.getFlag(flagName) <= value)	truth = true;
3113 		}
3114 		else if (comparison == ">=")
3115 		{
3116 			if (dsq->continuity.getFlag(flagName) >= value)	truth = true;
3117 		}
3118 
3119 		if (type == AND)
3120 		{
3121 			truth = (lastTruth && truth);
3122 		}
3123 		else if (type == OR)
3124 		{
3125 			truth = (lastTruth || truth);
3126 		}
3127 
3128 		if (next == "AND")
3129 		{
3130 			std::string restOfIt;
3131 			std::getline(is, restOfIt);
3132 			return doFlagCheck(restOfIt, AND, truth);
3133 		}
3134 		else if (next == "OR")
3135 		{
3136 			std::string restOfIt;
3137 			std::getline(is, restOfIt);
3138 			return doFlagCheck(restOfIt, OR, truth);
3139 		}
3140 
3141 		return truth;
3142 	}
3143 	return true;
3144 }
3145 
switchToSongMenu()3146 void Game::switchToSongMenu()
3147 {
3148 	dsq->screenTransition->capture();
3149 
3150 	toggleOptionsMenu(false);
3151 	toggleFoodMenu(false);
3152 	togglePetMenu(false);
3153 	toggleTreasureMenu(false);
3154 
3155 	toggleMainMenu(true);
3156 
3157 	dsq->screenTransition->transition(MENUPAGETRANSTIME);
3158 }
3159 
switchToFoodMenu()3160 void Game::switchToFoodMenu()
3161 {
3162 	dsq->screenTransition->capture();
3163 
3164 	toggleOptionsMenu(false);
3165 	togglePetMenu(false);
3166 	toggleMainMenu(false);
3167 	toggleTreasureMenu(false);
3168 
3169 	toggleFoodMenu(true);
3170 	dsq->screenTransition->transition(MENUPAGETRANSTIME);
3171 }
3172 
switchToPetMenu()3173 void Game::switchToPetMenu()
3174 {
3175 	dsq->screenTransition->capture();
3176 
3177 	toggleOptionsMenu(false);
3178 	toggleFoodMenu(false);
3179 	toggleMainMenu(false);
3180 	toggleTreasureMenu(false);
3181 
3182 	togglePetMenu(true);
3183 	dsq->screenTransition->transition(MENUPAGETRANSTIME);
3184 }
3185 
switchToTreasureMenu()3186 void Game::switchToTreasureMenu()
3187 {
3188 	dsq->screenTransition->capture();
3189 
3190 	toggleOptionsMenu(false);
3191 	toggleFoodMenu(false);
3192 	toggleMainMenu(false);
3193 	togglePetMenu(false);
3194 
3195 	toggleTreasureMenu(true);
3196 	dsq->screenTransition->transition(MENUPAGETRANSTIME);
3197 }
3198 
3199 /*
3200 IET_INVINCIBLE
3201 IET_HP
3202 IET_MAXHP
3203 IET_DEFENSE
3204 IET_SPEED
3205 IET_REGEN
3206 IET_ENERGY
3207 IET_BLIND
3208 IET_LIGHT
3209 IET_PETPOWER
3210 IET_WEB
3211 IET_LI
3212 IET_FISHPOISON
3213 IET_BITE
3214 IET_EAT
3215 IET_YUM
3216 IET_TRIP
3217 IET_RANDOM
3218 IET_POISON
3219 IET_ALLSTATUS
3220 */
3221 
3222 typedef std::vector<IngredientData> IngVec;
3223 
sortFood()3224 void Game::sortFood()
3225 {
3226 	/*
3227 	if (dsq->continuity.foodSortType == FOODSORT_UNSORTED)
3228 	{
3229 		if (dsq->continuity.sortByUnsort.empty())
3230 			for (int i = 0; i < dsq->continuity.ingredients.size(); i++)
3231 				dsq->continuity.sortByUnsort.push_back(FoodSortOrder(IT_NONE, IET_NONE, dsq->continuity.ingredients[i].name));
3232 	}
3233 	*/
3234 
3235 	std::vector<std::string> foodHolderNames;
3236 	foodHolderNames.resize(foodHolders.size());
3237 
3238 	for (int i = 0; i < foodHolders.size(); i++) {
3239 		IngredientData *ing = foodHolders[i]->getIngredient();
3240 		if (ing) {
3241 			foodHolderNames[i] = ing->name;
3242 			//errorLog(foodHolderNames[i]);
3243 			//foodHolders[i]->setIngredient(0);
3244 		}
3245 	}
3246 
3247 	dsq->continuity.foodSortType++;
3248 	if (dsq->continuity.foodSortType >= MAX_FOODSORT)
3249 		dsq->continuity.foodSortType = 0;
3250 
3251 	dsq->continuity.sortFood();
3252 
3253 	// rebuild the page
3254 
3255 	refreshFoodSlots(false);
3256 
3257 	/*
3258 	toggleFoodMenu(false);
3259 	toggleFoodMenu(true);
3260 	*/
3261 
3262 	dsq->sound->playSfx("shuffle");
3263 	dsq->sound->playSfx("menu-switch", 0.5);
3264 	dsq->spawnParticleEffect("menu-switch", worldLeftCenter, 0, 0, LR_HUD3, 1);
3265 
3266 	for (int i = 0; i < foodHolders.size(); i++) {
3267 		if (!foodHolderNames[i].empty()) {
3268 			IngredientData *ing = dsq->continuity.getIngredientHeldByName(foodHolderNames[i]);
3269 			foodHolders[i]->setIngredient(ing, false);
3270 
3271 			//foodHolders[i]->setIngredient(dsq->continuity.getIngredientByName(foodHolderNames[i]));
3272 			/*
3273 			if (!foodHolders[i]->foodHolderIngredient) {
3274 				errorLog("not found");
3275 			}
3276 			else {
3277 				std::ostringstream os;
3278 				os << "get: " << foodHolders[i]->foodHolderIngredient->name;
3279 				errorLog(os.str());
3280 			}
3281 			*/
3282 		}
3283 	}
3284 }
3285 
createInGameMenu()3286 void Game::createInGameMenu()
3287 {
3288 	float menuz = 4;
3289 	int i = 0;
3290 
3291 
3292 	menuBg = new Quad;
3293 	menuBg->setTexture("menu");
3294 	//menuBg->setWidthHeight(800);
3295 	//menuBg->scale = Vector(800.0f/1024.0f, 800.0f/1024.0f);
3296 	menuBgScale = Vector(800.0f/1024.0f, 800.0f/1024.0f);
3297 	menuBg->position = Vector(400,300,menuz);
3298 	menuBg->followCamera = 1;
3299 	//menuBg->shareAlphaWithChildren=true;
3300 	addRenderObject(menuBg, LR_MENU);
3301 
3302 
3303 	menuBg2 = new Quad;
3304 	menuBg2->setTexture("menu2");
3305 	menuBg2->position = Vector(0, 240);
3306 	menuBg->addChild(menuBg2, PM_POINTER);
3307 
3308 	float scale = menuBg->scale.x;
3309 	/*
3310 	songDescription = new BitmapText(&dsq->font);
3311 	songDescription->position = Vector(0,100);
3312 	songDescription->parentManagedPointer = 1;
3313 	menuBg->addChild(songDescription);
3314 	*/
3315 
3316 	options = new Quad;
3317 
3318 	options->renderQuad = false;
3319 
3320 	int sliderx = 250, slidery = 160, sliderd = 26;
3321 	int checkx=660, checky = 160, checkd = 26;
3322 
3323 	Quad *audio = new Quad("gui/audiovisual", Vector(200, 125));
3324 	options->addChild(audio, PM_POINTER);
3325 
3326 	Quad *controls = new Quad("gui/controls", Vector(600, 125));
3327 	options->addChild(controls, PM_POINTER);
3328 
3329 	/*
3330 	Quad *visual = new Quad("gui/visual", Vector(170, 300));
3331 	visual->parentManagedPointer = 1;
3332 	options->addChild(visual);
3333 	*/
3334 
3335 	/*
3336 	Quad *blurEffectsLabel = new Quad("gui/blurEffectsLabel.png", visual->position + Vector(-20,40));
3337 	blurEffectsLabel->parentManagedPointer = 1;
3338 	options->addChild(blurEffectsLabel);
3339 	*/
3340 
3341 	/*
3342 	blurEffectsCheck = new AquariaCheckBox();
3343 	blurEffectsCheck->position = visual->position + Vector(60, 40);
3344 	blurEffectsCheck->parentManagedPointer = 1;
3345 	options->addChild(blurEffectsCheck);
3346 	*/
3347 
3348 	Quad *controllabels = new Quad("gui/controllabels", Vector(0,0,0));
3349 	int w = controllabels->getWidth();
3350 	int h = controllabels->getHeight();
3351 	controllabels->position = Vector(checkx-16-w/2.0f, checky + h/2.0f - 14);
3352 	options->addChild(controllabels, PM_POINTER);
3353 
3354 
3355 
3356 	int scheckx=270;
3357 	int schecky=315;
3358 	int sw,sh;
3359 	int voptoffy = 26;
3360 
3361 	Quad *subtitleslabel = new Quad("gui/subtitles", Vector(0,0,0));
3362 	sw = subtitleslabel->getWidth();
3363 	sh = subtitleslabel->getHeight();
3364 	subtitleslabel->position = Vector(scheckx-16-sw*0.5f, schecky + sh/2.0f - 14);
3365 	options->addChild(subtitleslabel, PM_POINTER);
3366 
3367 	subtitlesCheck = new AquariaCheckBox();
3368 	subtitlesCheck->setValue(dsq->user.audio.subtitles);
3369 	subtitlesCheck->position = Vector(scheckx,schecky);
3370 	options->addChild(subtitlesCheck, PM_POINTER);
3371 
3372 	Quad *fullscreenLabel = new Quad("gui/fullscreen", Vector(0,0,0));
3373 	fullscreenLabel->position = Vector(scheckx-16-sw*0.5f, schecky + voptoffy + sh/2.0f - 14);
3374 	options->addChild(fullscreenLabel, PM_POINTER);
3375 
3376 	fullscreenCheck = new AquariaCheckBox();
3377 	fullscreenCheck->setValue(dsq->isFullscreen());
3378 	fullscreenCheck->position = Vector(scheckx,schecky + voptoffy);
3379 	options->addChild(fullscreenCheck, PM_POINTER);
3380 
3381 	Quad *resolutionLabel = new Quad("gui/resolution", Vector(0,0,0));
3382 	resolutionLabel->position = Vector(160, 260);
3383 	options->addChild(resolutionLabel, PM_POINTER);
3384 
3385 	resBox = new AquariaComboBox(Vector(0.7f, 1.0f));
3386 	resBox->position = Vector(196, 285);
3387 	for (i = 0; i < core->screenModes.size(); i++)
3388 	{
3389 		std::ostringstream os;
3390 		os << core->screenModes[i].x << "x" << core->screenModes[i].y;
3391 		if(core->screenModes[i].hz)
3392 			os << " (" << core->screenModes[i].hz << "hz)";
3393 		resBox->addItem(os.str());
3394 		if (core->screenModes[i].x == dsq->user.video.resx && core->screenModes[i].y == dsq->user.video.resy)
3395 		{
3396 			resBox->enqueueSelectItem(i);
3397 		}
3398 	}
3399 	options->addChild(resBox, PM_POINTER);
3400 
3401 	Quad *audiolabels = new Quad("gui/audiolabels", Vector(0,0,0));
3402 	w = audiolabels->getWidth();
3403 	h = audiolabels->getHeight();
3404 	audiolabels->position = Vector(sliderx-64-w/2.0f, slidery + h/2.0f - 14);
3405 	options->addChild(audiolabels, PM_POINTER);
3406 
3407 	musslider = new AquariaSlider();
3408 	musslider->setValue(dsq->user.audio.musvol);
3409 	musslider->position = Vector(sliderx,slidery+1*sliderd);
3410 	options->addChild(musslider, PM_POINTER);
3411 
3412 	sfxslider = new AquariaSlider();
3413 	sfxslider->setValue(dsq->user.audio.sfxvol);
3414 	sfxslider->position = Vector(sliderx,slidery);
3415 	options->addChild(sfxslider, PM_POINTER);
3416 
3417 	voxslider = new AquariaSlider();
3418 	voxslider->setValue(dsq->user.audio.voxvol);
3419 	voxslider->position = Vector(sliderx,slidery+2*sliderd);
3420 	options->addChild(voxslider, PM_POINTER);
3421 
3422 
3423 	flipInputButtonsCheck = new AquariaCheckBox();
3424 	flipInputButtonsCheck->setValue(dsq->user.control.flipInputButtons);
3425 	flipInputButtonsCheck->position = Vector(checkx,checky);
3426 	options->addChild(flipInputButtonsCheck, PM_POINTER);
3427 
3428 	micInputCheck = 0;
3429 
3430 	toolTipsCheck = new AquariaCheckBox();
3431 	toolTipsCheck->setValue(dsq->user.control.toolTipsOn);
3432 	toolTipsCheck->position = Vector(checkx,checky+1*checkd);
3433 	options->addChild(toolTipsCheck, PM_POINTER);
3434 
3435 	autoAimCheck = new AquariaCheckBox();
3436 	autoAimCheck->setValue(dsq->user.control.autoAim);
3437 	autoAimCheck->position = Vector(checkx,checky+2*checkd);
3438 	options->addChild(autoAimCheck, PM_POINTER);
3439 
3440 	targetingCheck = new AquariaCheckBox();
3441 	targetingCheck->setValue(dsq->user.control.targeting);
3442 	targetingCheck->position = Vector(checkx,checky+3*checkd);
3443 	options->addChild(targetingCheck, PM_POINTER);
3444 
3445 
3446 
3447 	opt_save = new AquariaMenuItem;
3448 	opt_save->useQuad("gui/Apply");
3449 	opt_save->useGlow("particles/glow", 100, 50);
3450 	opt_save->event.set(MakeFunctionEvent(Game, onOptionsSave));
3451 	opt_save->position = opt_save_original;
3452 	opt_save->alpha = 0;
3453 	addRenderObject(opt_save, LR_MENU);
3454 
3455 	opt_cancel = new AquariaMenuItem;
3456 	opt_cancel->useQuad("gui/Cancel");
3457 	opt_cancel->useGlow("particles/glow", 100, 50);
3458 	opt_cancel->event.set(MakeFunctionEvent(Game, onOptionsCancel));
3459 	opt_cancel->position = opt_cancel_original;
3460 	opt_cancel->alpha = 0;
3461 	addRenderObject(opt_cancel, LR_MENU);
3462 
3463 	options->shareAlphaWithChildren = 1;
3464 	options->alpha = 0;
3465 	options->followCamera = 1;
3466 	addRenderObject(options, LR_MENU);
3467 
3468 	scale = 1;
3469 	songSlots.clear();
3470 	//songSlots.resize(3);
3471 	songSlots.resize(10);
3472 	// rewrite this: so you can hide / ignore certain songs, etc
3473 	//songSlots.resize(dsq->continuity.getSongBankSize());
3474 	//Vector center(-235, -50);
3475 	Vector center(-230, -50), rightCenter(230, -50);
3476 
3477 	energyIdol = new Quad("formupgrades/energyidol-charged", Vector(40,0));
3478 	menuBg->addChild(energyIdol, PM_POINTER);
3479 
3480 	liCrystal = new Quad("gui/li-crystal", Vector(0,0));
3481 	menuBg->addChild(liCrystal, PM_POINTER);
3482 
3483 	songBubbles = new Quad("gui/SongBubbles", Vector(-center.x, center.y));
3484 	menuBg->addChild(songBubbles, PM_POINTER);
3485 
3486 
3487 	// Vector(575,250);
3488 
3489 
3490 	songLabel = new BitmapText(&dsq->smallFont);
3491 	{
3492 		songLabel->alpha = 0;
3493 		songLabel->setAlign(ALIGN_CENTER);
3494 		songLabel->followCamera = 1;
3495 		songLabel->setFontSize(20);
3496 		songLabel->position = Vector(-center.x, center.y) + Vector(0, -15); //+ Vector(10, -10);
3497 		songLabel->scale = Vector(1.2, 1.2);
3498 	}
3499 	menuBg->addChild(songLabel, PM_POINTER);
3500 
3501 
3502 
3503 
3504 	ToolTip *tip = 0;
3505 
3506 	foodTips.clear();
3507 	songTips.clear();
3508 	petTips.clear();
3509 	treasureTips.clear();
3510 
3511 	tip = new ToolTip;
3512 	tip->alpha = 0;
3513 	tip->setCircularAreaFromCenter(worldLeftCenter, 240);
3514 	tip->setText(dsq->continuity.stringBank.get(0), Vector(200,450), 350);
3515 	addRenderObject(tip, LR_HUD);
3516 	foodTips.push_back(tip);
3517 
3518 
3519 	tip = new ToolTip;
3520 	tip->alpha = 0;
3521 	tip->setCircularAreaFromCenter(worldRightCenter, 240);
3522 	tip->setText(dsq->continuity.stringBank.get(1), Vector(600,450), 350);
3523 	addRenderObject(tip, LR_HUD);
3524 	foodTips.push_back(tip);
3525 
3526 
3527 
3528 	tip = new ToolTip;
3529 	tip->alpha = 0;
3530 	tip->setCircularAreaFromCenter(worldLeftCenter, 240);
3531 	tip->setText(dsq->continuity.stringBank.get(14), Vector(200,450), 350);
3532 	addRenderObject(tip, LR_HUD);
3533 	songTips.push_back(tip);
3534 
3535 
3536 	/*
3537 	tip = new ToolTip;
3538 	tip->alpha = 0;
3539 	tip->setAreaFromCenter(Vector(400,300), 800, 600);
3540 	tip->setText(dsq->continuity.stringBank.get(16), Vector(400,300), 400);
3541 	addRenderObject(tip, LR_HUD);
3542 	petTips.push_back(tip);
3543 	*/
3544 
3545 	tip = new ToolTip;
3546 	tip->alpha = 0;
3547 	tip->setCircularAreaFromCenter(worldLeftCenter, 240);
3548 	tip->setText(dsq->continuity.stringBank.get(17), Vector(200,450), 350);
3549 	addRenderObject(tip, LR_HUD);
3550 	petTips.push_back(tip);
3551 
3552 	tip = new ToolTip;
3553 	tip->alpha = 0;
3554 	tip->setAreaFromCenter(Vector(400,350), 150, 50);
3555 	tip->setText(dsq->continuity.stringBank.get(15), Vector(400,450), 450);
3556 	addRenderObject(tip, LR_HUD);
3557 	songTips.push_back(tip);
3558 	foodTips.push_back(tip);
3559 	petTips.push_back(tip);
3560 	treasureTips.push_back(tip);
3561 
3562 	int radius = 118;
3563 	int food = 0;
3564 
3565 	keyConfigButton = new AquariaMenuItem;
3566 	keyConfigButton->useQuad("gui/keyconfig-button");
3567 	keyConfigButton->useGlow("particles/glow", 128, 40);
3568 	keyConfigButton->position = worldRightCenter + Vector(0, 80);
3569 	keyConfigButton->alpha = 0;
3570 	keyConfigButton->scale = Vector(0.8, 0.8);
3571 	keyConfigButton->event.set(MakeFunctionEvent(Game, onKeyConfig));
3572 	//keyConfigButton->setCanDirMove(false);
3573 	addRenderObject(keyConfigButton, LR_MENU);
3574 
3575 
3576 
3577 	group_keyConfig = new RenderObject;
3578 
3579 	/*
3580 	Quad *kbg = new Quad("gui/keyconfig-menu", Vector(400,300));
3581 	kbg->setWidthHeight(800, 800);
3582 	group_keyConfig->addChild(kbg);
3583 	*/
3584 
3585 	//Quad *kcb = new Quad;
3586 	RoundedRect *kcb = new RoundedRect();
3587 	//kcb->color = 0;
3588 	//kcb->alphaMod = 0.75;
3589 	kcb->position = Vector(400,276 - 10);
3590 	kcb->setWidthHeight(580, 455, 10);
3591 	group_keyConfig->addChild(kcb, PM_POINTER);
3592 
3593 	int offy = -20;
3594 
3595 #define SB(x) dsq->continuity.stringBank.get(x)
3596 
3597 	TTFText *header_action = new TTFText(&dsq->fontArialSmall);
3598 	header_action->setText(SB(2101));
3599 	header_action->position = Vector(140, 80+offy);
3600 	group_keyConfig->addChild(header_action, PM_POINTER);
3601 
3602 	TTFText *header_key1 = new TTFText(&dsq->fontArialSmall);
3603 	header_key1->setText(SB(2102));
3604 	header_key1->position = Vector(350, 80+offy);
3605 	header_key1->setAlign(ALIGN_CENTER);
3606 	group_keyConfig->addChild(header_key1, PM_POINTER);
3607 
3608 	TTFText *header_key2 = new TTFText(&dsq->fontArialSmall);
3609 	header_key2->setText(SB(2103));
3610 	header_key2->position = Vector(475, 80+offy);
3611 	header_key2->setAlign(ALIGN_CENTER);
3612 	group_keyConfig->addChild(header_key2, PM_POINTER);
3613 
3614 	TTFText *header_joy = new TTFText(&dsq->fontArialSmall);
3615 	header_joy->setText(SB(2104));
3616 	header_joy->position = Vector(600, 80+offy);
3617 	header_joy->setAlign(ALIGN_CENTER);
3618 	group_keyConfig->addChild(header_joy, PM_POINTER);
3619 
3620 	addKeyConfigLine(group_keyConfig, SB(2105), "lmb",					100+offy, 0, 0, 0);
3621 	addKeyConfigLine(group_keyConfig, SB(2106), "rmb",					120+offy, 0, 0, 0);
3622 	addKeyConfigLine(group_keyConfig, SB(2107), "PrimaryAction",		140+offy);
3623 	addKeyConfigLine(group_keyConfig, SB(2108), "SecondaryAction",		160+offy);
3624 	addKeyConfigLine(group_keyConfig, SB(2109), "SwimUp",				180+offy);
3625 	addKeyConfigLine(group_keyConfig, SB(2110), "SwimDown",				200+offy);
3626 	addKeyConfigLine(group_keyConfig, SB(2111), "SwimLeft",				220+offy);
3627 	addKeyConfigLine(group_keyConfig, SB(2112), "SwimRight",			240+offy);
3628 	addKeyConfigLine(group_keyConfig, SB(2113), "Roll",					260+offy);
3629 	addKeyConfigLine(group_keyConfig, SB(2114), "Revert",				280+offy);
3630 	addKeyConfigLine(group_keyConfig, SB(2115), "WorldMap",				300+offy);
3631 	addKeyConfigLine(group_keyConfig, SB(2116), "Escape",				320+offy, 1, 0, 0);
3632 
3633 	AquariaKeyConfig* s1x = addAxesConfigLine(group_keyConfig, SB(2117), "s1ax", 340+offy, 0);
3634 	AquariaKeyConfig* s1y = addAxesConfigLine(group_keyConfig, SB(2118), "s1ay", 340+offy, 130);
3635 	AquariaKeyConfig* s2x = addAxesConfigLine(group_keyConfig, SB(2119), "s2ax", 340+offy, 260);
3636 	AquariaKeyConfig* s2y = addAxesConfigLine(group_keyConfig, SB(2120), "s2ay", 340+offy, 380);
3637 
3638 	s1x->setDirMove(DIR_LEFT, s1x);
3639 	s1x->setDirMove(DIR_RIGHT, s1y);
3640 
3641 	s1y->setDirMove(DIR_LEFT, s1x);
3642 	s1y->setDirMove(DIR_RIGHT, s2x);
3643 
3644 	s2x->setDirMove(DIR_LEFT, s1y);
3645 	s2x->setDirMove(DIR_RIGHT, s2y);
3646 
3647 	s2y->setDirMove(DIR_LEFT, s2x);
3648 	s2y->setDirMove(DIR_RIGHT, s2y);
3649 
3650 	offy += 20;
3651 
3652 	addKeyConfigLine(group_keyConfig, SB(2121), "PrevPage",		340+offy);
3653 	addKeyConfigLine(group_keyConfig, SB(2122), "NextPage",		360+offy);
3654 	addKeyConfigLine(group_keyConfig, SB(2123), "CookFood",		380+offy);
3655 	addKeyConfigLine(group_keyConfig, SB(2124), "FoodLeft",		400+offy);
3656 	addKeyConfigLine(group_keyConfig, SB(2125), "FoodRight",	420+offy);
3657 	addKeyConfigLine(group_keyConfig, SB(2126), "FoodDrop",		440+offy);
3658 
3659 	addKeyConfigLine(group_keyConfig, SB(2127), "Look",			460+offy);
3660 
3661 	addKeyConfigLine(group_keyConfig, SB(2128), "ToggleHelp",	480+offy);
3662 
3663 #undef SB
3664 
3665 	group_keyConfig->shareAlphaWithChildren = 1;
3666 	group_keyConfig->followCamera = 1;
3667 	group_keyConfig->alpha = 0;
3668 	group_keyConfig->setHidden(true);
3669 
3670 	group_keyConfig->position = Vector(0, -40);
3671 
3672 	addRenderObject(group_keyConfig, LR_OVERLAY);
3673 
3674 
3675 	cook = new AquariaMenuItem;
3676 	cook->useQuad("Gui/cook-button");
3677 	cook->useGlow("particles/glow", 128, 40);
3678 	cook->position = worldRightCenter + Vector(0, -120);
3679 	cook->alpha = 0;
3680 	cook->scale = Vector(0.8, 0.8);
3681 	cook->event.set(MakeFunctionEvent(Game, onCook));
3682 	cook->setCanDirMove(false);
3683 	addRenderObject(cook, LR_MENU);
3684 
3685 	foodSort = new AquariaMenuItem;
3686 	foodSort->useQuad("gui/sort");
3687 	foodSort->useSound("click");
3688 	foodSort->useGlow("particles/glow", 32,32);
3689 	foodSort->position = worldLeftCenter + Vector(-100, -100);
3690 	foodSort->event.set(MakeFunctionEvent(Game, sortFood));
3691 	foodSort->alpha = 0;
3692 	addRenderObject(foodSort, LR_MENU);
3693 
3694 	recipes = new AquariaMenuItem;
3695 	recipes->useQuad("Gui/recipes-button");
3696 	recipes->useGlow("particles/glow", 128, 32);
3697 	recipes->position = worldLeftCenter + Vector(-40, 140);
3698 	recipes->alpha = 0;
3699 	recipes->scale = Vector(0.8, 0.8);
3700 	recipes->event.set(MakeFunctionEvent(Game, onRecipes));
3701 	addRenderObject(recipes, LR_MENU);
3702 
3703 	use = new AquariaMenuItem;
3704 	use->useQuad("Gui/use-button");
3705 	use->useGlow("particles/glow", 128, 64);
3706 	use->position = worldRightCenter + Vector(0, -120);
3707 	use->alpha = 0;
3708 	use->scale = Vector(0.8, 0.8);
3709 	use->event.set(MakeFunctionEvent(Game, onUseTreasure));
3710 	addRenderObject(use, LR_MENU);
3711 
3712 	prevFood = new AquariaMenuItem;
3713 	prevFood->useQuad("Gui/arrow-left");
3714 	prevFood->useSound("click");
3715 	prevFood->useGlow("particles/glow", 64, 32);
3716 	prevFood->position = worldLeftCenter + Vector(-50, -130);
3717 	prevFood->alpha = 0;
3718 	prevFood->event.set(MakeFunctionEvent(Game, onPrevFoodPage));
3719 	prevFood->scale = Vector(0.6, 0.6);
3720 	prevFood->setCanDirMove(false);
3721 	addRenderObject(prevFood, LR_MENU);
3722 
3723 	nextFood = new AquariaMenuItem;
3724 	nextFood->useQuad("Gui/arrow-right");
3725 	nextFood->useSound("click");
3726 	nextFood->useGlow("particles/glow", 64, 32);
3727 	nextFood->position = worldLeftCenter + Vector(50, -130);
3728 	nextFood->alpha = 0;
3729 	nextFood->setCanDirMove(false);
3730 	nextFood->event.set(MakeFunctionEvent(Game, onNextFoodPage));
3731 	nextFood->scale = Vector(0.6, 0.6);
3732 	addRenderObject(nextFood, LR_MENU);
3733 
3734 	prevTreasure = new AquariaMenuItem;
3735 	prevTreasure->useQuad("Gui/arrow-left");
3736 	prevTreasure->useSound("click");
3737 	prevTreasure->useGlow("particles/glow", 64, 32);
3738 	prevTreasure->position = worldLeftCenter + Vector(-50, -130);
3739 	prevTreasure->alpha = 0;
3740 	prevTreasure->setCanDirMove(false);
3741 	prevTreasure->scale = Vector(0.6, 0.6);
3742 	prevTreasure->event.set(MakeFunctionEvent(Game, onPrevTreasurePage));
3743 	prevTreasure->setCanDirMove(false);
3744 	addRenderObject(prevTreasure, LR_MENU);
3745 
3746 	nextTreasure = new AquariaMenuItem;
3747 	nextTreasure->useQuad("Gui/arrow-right");
3748 	nextTreasure->useSound("click");
3749 	nextTreasure->useGlow("particles/glow", 64, 32);
3750 	nextTreasure->position = worldLeftCenter + Vector(50, -130);
3751 	nextTreasure->alpha = 0;
3752 	nextTreasure->scale = Vector(0.6, 0.6);
3753 	nextTreasure->event.set(MakeFunctionEvent(Game, onNextTreasurePage));
3754 	nextTreasure->setCanDirMove(false);
3755 	addRenderObject(nextTreasure, LR_MENU);
3756 
3757 	circlePageNum = new BitmapText(&dsq->smallFont);
3758 	circlePageNum->color = Vector(0,0,0);
3759 	circlePageNum->position = worldLeftCenter + Vector(0, -142);
3760 	circlePageNum->alpha = 0;
3761 	circlePageNum->followCamera = 1;
3762 	addRenderObject(circlePageNum, LR_MENU);
3763 
3764 	foodHolders.resize(3);
3765 	int holders=0;
3766 	for (i = 0; i < foodHolders.size(); i++)
3767 	{
3768 		foodHolders[i] = new FoodHolder(i);
3769 		foodHolders[i]->alpha = 0;
3770 
3771 		float angle = (float(holders)/float(foodHolders.size()))*PI*2;
3772 		foodHolders[i]->position = rightCenter + Vector(sinf(angle), cosf(angle))*radius;
3773 		holders ++;
3774 
3775 		menuBg->addChild(foodHolders[i], PM_POINTER);
3776 	}
3777 
3778 	previewRecipe = new Quad;
3779 	previewRecipe->alphaMod = 0.75;
3780 	previewRecipe->followCamera = 1;
3781 	previewRecipe->alpha = 0;
3782 	previewRecipe->scale = Vector(0.7, 0.7);
3783 	previewRecipe->scale.interpolateTo(Vector(0.9, 0.9), 0.5, -1, 1, 1);
3784 	previewRecipe->position = worldRightCenter;
3785 	addRenderObject(previewRecipe, LR_MENU);
3786 
3787 	showRecipe = new Quad();
3788 	showRecipe->followCamera = 1;
3789 	showRecipe->position = Vector(575,250);
3790 	addRenderObject(showRecipe, LR_MENU);
3791 
3792 	float scrollx = 555;
3793 	recipeMenu.scroll = new Quad("gui/recipe-scroll", Vector(scrollx, 200));
3794 	recipeMenu.scroll->followCamera = 1;
3795 	recipeMenu.scroll->alpha = 0;
3796 	addRenderObject(recipeMenu.scroll, LR_RECIPES); // LR_HUD3
3797 
3798 	recipeMenu.scrollEnd = new Quad("gui/recipe-scroll-end", Vector(scrollx, 400));
3799 	recipeMenu.scrollEnd->followCamera = 1;
3800 	recipeMenu.scrollEnd->alpha = 0;
3801 	addRenderObject(recipeMenu.scrollEnd, LR_RECIPES);
3802 
3803 	recipeMenu.header = new BitmapText(&dsq->font);
3804 	recipeMenu.header->color = 0;
3805 	recipeMenu.header->followCamera = 1;
3806 	recipeMenu.header->setText(dsq->continuity.stringBank.get(2007));
3807 	recipeMenu.header->alpha = 0;
3808 	recipeMenu.header->position = Vector(scrollx, 5); //10
3809 	addRenderObject(recipeMenu.header, LR_RECIPES);
3810 
3811 	recipeMenu.page = new BitmapText(&dsq->smallFont);
3812 	recipeMenu.page->color = 0;
3813 	recipeMenu.page->followCamera = 1;
3814 	recipeMenu.page->position = Vector(scrollx, 400);
3815 	recipeMenu.page->setText(dsq->continuity.stringBank.get(2006));
3816 	recipeMenu.page->alpha = 0;
3817 	addRenderObject(recipeMenu.page, LR_RECIPES);
3818 
3819 	recipeMenu.prevPage = new AquariaMenuItem;
3820 	recipeMenu.prevPage->useQuad("Gui/arrow-left");
3821 	recipeMenu.prevPage->useSound("click");
3822 	recipeMenu.prevPage->useGlow("particles/glow", 64, 32);
3823 	recipeMenu.prevPage->position = Vector(scrollx - 150, 410);
3824 	recipeMenu.prevPage->alpha = 0;
3825 	recipeMenu.prevPage->event.set(MakeFunctionEvent(Game, onPrevRecipePage));
3826 	recipeMenu.prevPage->scale = Vector(0.8, 0.8);
3827 	addRenderObject(recipeMenu.prevPage, LR_RECIPES);
3828 
3829 	recipeMenu.nextPage = new AquariaMenuItem;
3830 	recipeMenu.nextPage->useQuad("Gui/arrow-right");
3831 	recipeMenu.nextPage->useSound("click");
3832 	recipeMenu.nextPage->useGlow("particles/glow", 64, 32);
3833 	recipeMenu.nextPage->position = Vector(scrollx + 150, 410);
3834 	recipeMenu.nextPage->alpha = 0;
3835 	recipeMenu.nextPage->event.set(MakeFunctionEvent(Game, onNextRecipePage));
3836 	recipeMenu.nextPage->scale = Vector(0.8, 0.8);
3837 	addRenderObject(recipeMenu.nextPage, LR_RECIPES);
3838 
3839 
3840 	petSlots.resize(dsq->continuity.petData.size());
3841 	for (i = 0; i < petSlots.size(); i++)
3842 	{
3843 		PetData *p = dsq->continuity.getPetData(i);
3844 		if (p)
3845 		{
3846 			petSlots[i] = new PetSlot(i);
3847 			petSlots[i]->alpha = 0;
3848 			float angle = (float(i)/float(petSlots.size()))*PI*2;
3849 			petSlots[i]->position = center + Vector(sinf(angle), cosf(angle))*(radius*0.9f);
3850 			menuBg->addChild(petSlots[i], PM_POINTER);
3851 		}
3852 	}
3853 
3854 	foodHolders.resize(4);
3855 	foodHolders[3] = new FoodHolder(-1, true);
3856 	foodHolders[3]->alpha = 0;
3857 	foodHolders[3]->position = rightCenter + Vector(96, 150);
3858 	menuBg->addChild(foodHolders[3], PM_POINTER);
3859 
3860 
3861 
3862 
3863 
3864 	int outer = 0;
3865 	int inner = 0;
3866 	for (i = 0; i < songSlots.size(); i++)
3867 	{
3868 		songSlots[i] = new SongSlot(i);
3869 		float angle = 0;
3870 		SongType s = (SongType)dsq->continuity.getSongTypeBySlot(i);
3871 		if (dsq->continuity.isSongTypeForm(s))
3872 		{
3873 			angle = (float(outer)/float(numForms))*PI*2;
3874 			songSlots[i]->position = center + Vector(sinf(angle), cosf(angle))*radius;
3875 			outer ++;
3876 		}
3877 		else
3878 		{
3879 			angle = (float(inner)/float(songSlots.size()-numForms))*PI*2 + PI;
3880 			songSlots[i]->position = center + Vector(sinf(angle), cosf(angle))*radius*0.4f;
3881 			inner ++;
3882 		}
3883 		menuBg->addChild(songSlots[i], PM_POINTER);
3884 	}
3885 	menuSongs = 0;
3886 
3887 	menuMoney = menuEXP = 0;
3888 
3889 	menuDescription = new BitmapText(&dsq->smallFont);
3890 	menuDescription->setFontSize(14);
3891 	menuDescription->position = Vector(400, 450);
3892 	menuDescription->setAlign(ALIGN_CENTER);
3893 	menuDescription->setWidth(400);
3894 	menuDescription->followCamera = 1;
3895 	menuDescription->alpha = 0;
3896 	addRenderObject(menuDescription, LR_MENU);
3897 
3898 	currentInventoryPage = 0;
3899 
3900 	int areYouShim = -25;
3901 	eAre = new Quad;
3902 	eAre->position = Vector(400,448+areYouShim);
3903 	eAre->setTexture("AreYouSure");
3904 	eAre->alpha = 0;
3905 	eAre->followCamera = 1;
3906 	addRenderObject(eAre, LR_MENU);
3907 
3908 	eYes = new AquariaMenuItem;
3909 	eYes->position = Vector(400-100,516+areYouShim);
3910 	eYes->useQuad("Yes");
3911 	eYes->useGlow("particles/glow", 100, 32);
3912 	eYes->event.set(MakeFunctionEvent(Game, onExitCheckYes));
3913 	eYes->alpha = 0;
3914 	eYes->shareAlpha = 1;
3915 	addRenderObject(eYes, LR_MENU);
3916 
3917 	eNo = new AquariaMenuItem;
3918 	eNo->position = Vector(400+100,516+areYouShim);
3919 	eNo->useQuad("No");
3920 	eNo->useGlow("particles/glow", 100, 32);
3921 	eNo->event.set(MakeFunctionEvent(Game, onExitCheckNo));
3922 	eNo->alpha = 0;
3923 	eNo->shareAlpha = 1;
3924 	addRenderObject(eNo, LR_MENU);
3925 
3926 	eNo->setDirMove(DIR_LEFT, eYes);
3927 	eYes->setDirMove(DIR_RIGHT, eNo);
3928 
3929 
3930 
3931 	menu.resize(10);
3932 	for (i = 0; i < menu.size(); i++)
3933 		menu[i] = new AquariaMenuItem;
3934 
3935 	int ty = 530;
3936 	//menu[0]->setLabel("Continue");
3937 	menu[0]->event.set(MakeFunctionEvent(Game, onInGameMenuContinue));
3938 	menu[0]->useGlow("particles/glow", 200, 100);
3939 	//menu[0]->position = Vector(150, 550);
3940 	menu[0]->position = Vector(150-30, ty-10);
3941 
3942 	//menu[1]->setLabel("Exit");
3943 	menu[1]->useGlow("particles/glow", 200, 100);
3944 	menu[1]->event.set(MakeFunctionEvent(Game, onInGameMenuExit));
3945 	//menu[1]->position = Vector(800-150, 550);
3946 	//menu[1]->position = Vector(800-150+30, ty);
3947 	menu[1]->position = Vector(800-150+20, ty-10);
3948 
3949 	menu[2]->setLabel("DebugSave");
3950 	menu[2]->event.set(MakeFunctionEvent(Game, onDebugSave));
3951 	menu[2]->position = Vector(400,ty+60);
3952 	if (!dsq->isDeveloperKeys())
3953 		menu[2]->position = Vector(400, 12000);
3954 	menu[2]->setCanDirMove(false);
3955 
3956 	menu[3]->event.set(MakeFunctionEvent(Game, onLips));
3957 	menu[3]->useGlow("particles/glow", 64, 64);
3958 	//menu[0]->position = Vector(150, 550);
3959 	menu[3]->position = Vector(400, 195);
3960 	menu[3]->setCanDirMove(false);
3961 
3962 	lips = menu[3];
3963 
3964 	// options
3965 	menu[4]->event.set(MakeFunctionEvent(Game, onOptionsMenu));
3966 	menu[4]->useGlow("particles/glow", 200, 32);
3967 	menu[4]->position = Vector(400,ty+10);
3968 
3969 	int gs = 40;
3970 
3971 	menu[5]->event.set(MakeFunctionEvent(Game, switchToSongMenu));
3972 	menu[5]->useQuad("gui/icon-songs");
3973 	menu[5]->useGlow("particles/glow", gs, gs);
3974 	menu[5]->useSound("Click");
3975 	menu[5]->position = Vector(400-60, 350);
3976 
3977 	menuIconGlow = new Quad("particles/glow", menu[5]->position);
3978 	menuIconGlow->alphaMod = 0.4;
3979 	menuIconGlow->alpha = 0;
3980 	menuIconGlow->setWidthHeight(80, 80);
3981 	menuIconGlow->setBlendType(RenderObject::BLEND_ADD);
3982 	menuIconGlow->followCamera = 1;
3983 	addRenderObject(menuIconGlow, LR_MENU);
3984 
3985 	menu[6]->event.set(MakeFunctionEvent(Game, switchToFoodMenu));
3986 	menu[6]->useQuad("gui/icon-food");
3987 	menu[6]->useGlow("particles/glow", gs, gs);
3988 	menu[6]->useSound("Click");
3989 	menu[6]->position = Vector(400-20, 350);
3990 
3991 	menu[7]->event.set(MakeFunctionEvent(Game, switchToPetMenu));
3992 	menu[7]->useQuad("gui/icon-pets");
3993 	menu[7]->useGlow("particles/glow", gs, gs);
3994 	menu[7]->useSound("Click");
3995 	menu[7]->position = Vector(400+20, 350);
3996 
3997 	menu[8]->event.set(MakeFunctionEvent(Game, switchToTreasureMenu));
3998 	menu[8]->useQuad("gui/icon-treasures");
3999 	menu[8]->useGlow("particles/glow", gs, gs);
4000 	menu[8]->useSound("Click");
4001 	menu[8]->position = Vector(400+60, 350);
4002 
4003 	menu[9]->event.set(MakeFunctionEvent(Game, toggleHelpScreen));
4004 	menu[9]->useQuad("gui/icon-help");
4005 	menu[9]->useGlow("particles/glow", gs, gs);
4006 	menu[9]->useSound("Click");
4007 	menu[9]->position = Vector(400+60*3, 410);
4008 
4009 	/*
4010 	menu[9]->event.set(MakeFunctionEvent(Game, sortFood));
4011 	menu[9]->setLabel("sort food");
4012 	menu[9]->position = Vector(100,100);
4013 	*/
4014 
4015 	for (i = 0; i < menu.size(); i++)
4016 	{
4017 		addRenderObject(menu[i], LR_MENU);
4018 		menu[i]->alpha = 0;
4019 	}
4020 
4021 	((AquariaMenuItem*)menu[5])->setDirMove(DIR_DOWN, ((AquariaMenuItem*)menu[0]));
4022 	((AquariaMenuItem*)menu[6])->setDirMove(DIR_DOWN, ((AquariaMenuItem*)menu[4]));
4023 	((AquariaMenuItem*)menu[7])->setDirMove(DIR_DOWN, ((AquariaMenuItem*)menu[4]));
4024 	((AquariaMenuItem*)menu[8])->setDirMove(DIR_DOWN, ((AquariaMenuItem*)menu[1]));
4025 
4026 	((AquariaMenuItem*)menu[0])->setDirMove(DIR_UP, ((AquariaMenuItem*)menu[5]));
4027 	((AquariaMenuItem*)menu[1])->setDirMove(DIR_UP, ((AquariaMenuItem*)menu[8]));
4028 
4029 	((AquariaMenuItem*)menu[4])->setDirMove(DIR_UP, ((AquariaMenuItem*)menu[6]));
4030 
4031 
4032 
4033 // ---------- FOOD MENU
4034 
4035 	foodSlots.resize(foodPageSize);
4036 
4037 	Vector worldCenter(222, 252);
4038 
4039 	int foodSlotRadius = 96;
4040 	for (i = 0; i < foodSlots.size(); i++)
4041 	{
4042 		foodSlots[i] = new FoodSlot(i);
4043 
4044 		float angle = (float(food)/float(foodSlots.size()))*PI*2;
4045 		foodSlots[i]->position = worldCenter + Vector(sinf(angle), cosf(angle))*foodSlotRadius;
4046 
4047 		foodSlots[i]->setOriginalPosition(foodSlots[i]->position);
4048 
4049 		food ++;
4050 
4051 		foodSlots[i]->alphaMod = 0;
4052 
4053 		foodSlots[i]->followCamera = 1;
4054 
4055 		foodSlots[i]->scaleFactor = 0.75;
4056 
4057 		//foodSlots[i]->parentManagedPointer = 1;
4058 		//menuBg->addChild(foodSlots[i]);
4059 		//foodSlots[i]->position = menuBg->getWorldCollidePosition(foodSlots[i]->position);
4060 		addRenderObject(foodSlots[i], LR_HUD2);
4061 	}
4062 
4063 
4064 	foodLabel = new BitmapText(&dsq->smallFont);
4065 	{
4066 		foodLabel->alpha = 0;
4067 		foodLabel->setAlign(ALIGN_CENTER);
4068 		foodLabel->followCamera = 1;
4069 		foodLabel->setFontSize(20);
4070 		foodLabel->position = center - Vector(0, 16) + Vector(0,-32);
4071 		foodLabel->scale = Vector(1, 1);
4072 	}
4073 	menuBg->addChild(foodLabel, PM_POINTER);
4074 
4075 	foodDescription = new BitmapText(&dsq->smallFont);
4076 	{
4077 		foodDescription->alpha = 0;
4078 		foodDescription->setAlign(ALIGN_CENTER);
4079 		foodDescription->followCamera = 1;
4080 		foodDescription->position = center + Vector(0, 8) + Vector(0,-32);
4081 		foodDescription->scale = Vector(0.8, 0.8);
4082 
4083 		foodDescription->setWidth(240);
4084 	}
4085 	menuBg->addChild(foodDescription, PM_POINTER);
4086 
4087 
4088 // ---------- TREASURES
4089 
4090 
4091 	int treasureSlotRadius = 96;
4092 
4093 	treasureSlots.resize(treasurePageSize);
4094 
4095 	for (i = 0; i < treasureSlots.size(); i++)
4096 	{
4097 		treasureSlots[i] = new TreasureSlot(i);
4098 
4099 
4100 		float angle = (float(i)/float(treasureSlots.size()))*PI*2;
4101 		treasureSlots[i]->position = worldCenter + Vector(sinf(angle), cosf(angle))*treasureSlotRadius;
4102 
4103 		treasureSlots[i]->alphaMod = 0;
4104 
4105 		treasureSlots[i]->followCamera = 1;
4106 
4107 		//treasureSlots[i]->scaleFactor = 0.75;
4108 
4109 		addRenderObject(treasureSlots[i], LR_MENU);
4110 	}
4111 
4112 	treasureLabel = new BitmapText(&dsq->smallFont);
4113 	{
4114 		treasureLabel->alpha = 0;
4115 		treasureLabel->setAlign(ALIGN_CENTER);
4116 		treasureLabel->followCamera = 1;
4117 		treasureLabel->setFontSize(20);
4118 		treasureLabel->position = center - Vector(0, 16);
4119 		treasureLabel->scale = Vector(1, 1);
4120 	}
4121 	menuBg->addChild(treasureLabel, PM_POINTER);
4122 
4123 	treasureDescription = new ToolTip();
4124 	treasureDescription->alpha = 0;
4125 	treasureDescription->setAreaFromCenter(Vector(400,200), 800, 400);
4126 	treasureDescription->required = true;
4127 	addRenderObject(treasureDescription, LR_HUD);
4128 
4129 	foodTips.push_back(tip);
4130 
4131 	treasureCloseUp = new Quad();
4132 		treasureCloseUp->position = rightCenter;
4133 		treasureCloseUp->alpha = 0;
4134 	menuBg->addChild(treasureCloseUp, PM_POINTER);
4135 
4136 
4137 
4138 	menuBg->alpha = 0;
4139 }
4140 
onNextRecipePage()4141 void Game::onNextRecipePage()
4142 {
4143 	game->recipeMenu.goNextPage();
4144 }
4145 
onPrevRecipePage()4146 void Game::onPrevRecipePage()
4147 {
4148 	game->recipeMenu.goPrevPage();
4149 }
4150 
toggleOverrideZoom(bool on)4151 void Game::toggleOverrideZoom(bool on)
4152 {
4153 	if (avatar)
4154 	{
4155 		if (on )
4156 		{
4157 			if (avatar->isEntityDead())
4158 				return;
4159 		}
4160 		if (!on && avatar->zoomOverriden == true)
4161 		{
4162 			dsq->globalScale.stop();
4163 			avatar->myZoom = dsq->globalScale;
4164 		}
4165 		avatar->zoomOverriden = on;
4166 	}
4167 }
4168 
addProgress()4169 void Game::addProgress()
4170 {
4171 	if (progressBar)
4172 	{
4173 		progressBar->progress();
4174 	}
4175 }
4176 
endProgress()4177 void Game::endProgress()
4178 {
4179 	if (progressBar)
4180 	{
4181 		progressBar->setLife(1);
4182 		progressBar->setDecayRate(1.0f/0.5f);
4183 		progressBar->fadeAlphaWithLife = 1;
4184 		progressBar = 0;
4185 	}
4186 }
4187 
loadSceneXML(std::string scene)4188 bool Game::loadSceneXML(std::string scene)
4189 {
4190 	bgSfxLoop = "";
4191 	airSfxLoop = "";
4192 	elementTemplatePack = "Main";
4193 	entitySaveData.clear();
4194 	std::string fn = getSceneFilename(scene);
4195 	if (!exists(fn))
4196 	{
4197 		//errorLog("Could not find [" + fn + "]");
4198 		//msg("Could not find map [" + fn + "]");
4199 		std::string s = "Could not find map [" + fn + "]";
4200 		dsq->screenMessage(s);
4201 		return false;
4202 	}
4203 	XMLDocument doc;
4204 	if(readXML(fn, doc) != XML_SUCCESS)
4205 	{
4206 		dsq->screenMessage("Could not load scene [" + fn + "] - Malformed XML");
4207 		return false;
4208 	}
4209 	if (saveFile)
4210 	{
4211 		delete saveFile;
4212 		saveFile = 0;
4213 	}
4214 	if (!saveFile)
4215 	{
4216 		saveFile = new XMLDocument();
4217 	}
4218 
4219 	addProgress();
4220 
4221 	clearObsRows();
4222 	warpAreas.clear();
4223 	XMLElement *lensFlare = doc.FirstChildElement("LensFlare");
4224 	while (lensFlare)
4225 	{
4226 		LensFlare *l = new LensFlare;
4227 		SimpleIStringStream is(lensFlare->Attribute("tex"));
4228 		int w = -1, h=-1;
4229 		w = atoi(lensFlare->Attribute("w"));
4230 		h = atoi(lensFlare->Attribute("h"));
4231 
4232 		std::string tex;
4233 		while (is >> tex)
4234 		{
4235 			if (!tex.empty())
4236 				l->addFlare(tex, Vector(1,1,1), w, h);
4237 		}
4238 		SimpleIStringStream is2(lensFlare->Attribute("inc"));
4239 		is2 >> l->inc;
4240 		l->maxLen = atoi(lensFlare->Attribute("maxLen"));
4241 		/*
4242 		l->addFlare("flares/flare0", Vector(1,1,0.5));
4243 		l->addFlare("flares/flare1", Vector(1,1,1));
4244 		l->addFlare("flares/flare2", Vector(0.5,1,1));
4245 		l->addFlare("flares/flare2", Vector(1,1,1));
4246 		*/
4247 		l->position = Vector(atoi(lensFlare->Attribute("x")),atoi(lensFlare->Attribute("y")));
4248 		addRenderObject(l, LR_LIGHTING);
4249 
4250 		XMLElement *lSF = saveFile->NewElement("LensFlare");
4251 		lSF->SetAttribute("inc", lensFlare->Attribute("inc"));
4252 		lSF->SetAttribute("x", lensFlare->Attribute("x"));
4253 		lSF->SetAttribute("y", lensFlare->Attribute("y"));
4254 		lSF->SetAttribute("tex", lensFlare->Attribute("tex"));
4255 		lSF->SetAttribute("w", lensFlare->Attribute("w"));
4256 		lSF->SetAttribute("h", lensFlare->Attribute("h"));
4257 		lSF->SetAttribute("maxLen", lensFlare->Attribute("maxLen"));
4258 		saveFile->InsertEndChild(lSF);
4259 
4260 		lensFlare = lensFlare->NextSiblingElement("LensFlare");
4261 	}
4262 	XMLElement *level = doc.FirstChildElement("Level");
4263 	if (level)
4264 	{
4265 		XMLElement *levelSF = saveFile->NewElement("Level");
4266 		if (level->Attribute("tileset"))
4267 		{
4268 			elementTemplatePack = level->Attribute("tileset");
4269 			loadElementTemplates(elementTemplatePack);
4270 			levelSF->SetAttribute("tileset", elementTemplatePack.c_str());
4271 		}
4272 		else if (level->Attribute("elementTemplatePack"))
4273 		{
4274 			elementTemplatePack = level->Attribute("elementTemplatePack");
4275 			loadElementTemplates(elementTemplatePack);
4276 			levelSF->SetAttribute("tileset", elementTemplatePack.c_str());
4277 		}
4278 		else
4279 			return false;
4280 
4281 		if (level->Attribute("waterLevel"))
4282 		{
4283 			useWaterLevel = true;
4284 			waterLevel = atoi(level->Attribute("waterLevel"));
4285 			saveWaterLevel = atoi(level->Attribute("waterLevel"));
4286 			levelSF->SetAttribute("waterLevel", waterLevel.x);
4287 		}
4288 		if (level->Attribute("worldMapIndex"))
4289 		{
4290 			worldMapIndex = atoi(level->Attribute("worldMapIndex"));
4291 			levelSF->SetAttribute("worldMapIndex", worldMapIndex);
4292 		}
4293 
4294 		if (level->Attribute("bgSfxLoop"))
4295 		{
4296 			bgSfxLoop = level->Attribute("bgSfxLoop");
4297 			levelSF->SetAttribute("bgSfxLoop", bgSfxLoop.c_str());
4298 		}
4299 		if (level->Attribute("airSfxLoop"))
4300 		{
4301 			airSfxLoop = level->Attribute("airSfxLoop");
4302 			levelSF->SetAttribute("airSfxLoop", airSfxLoop.c_str());
4303 		}
4304 		if (level->Attribute("bnat"))
4305 		{
4306 			bNatural = atoi(level->Attribute("bnat"));
4307 			levelSF->SetAttribute("bnat", 1);
4308 		}
4309 		else
4310 		{
4311 			bNatural = false;
4312 		}
4313 
4314 		/*
4315 		if (level->Attribute("darkLayer"))
4316 		{
4317 			int v = (atoi(level->Attribute("darkLayer")));
4318 
4319 			levelSF->SetAttribute("darkLayer", v);
4320 		}
4321 		*/
4322 		dsq->darkLayer.toggle(true);
4323 
4324 		if (level->Attribute("bgRepeat"))
4325 		{
4326 			SimpleIStringStream is(level->Attribute("bgRepeat"));
4327 			is >> backgroundImageRepeat;
4328 			levelSF->SetAttribute("bgRepeat", level->Attribute("bgRepeat"));
4329 		}
4330 		if (level->Attribute("cameraConstrained"))
4331 		{
4332 			SimpleIStringStream is(level->Attribute("cameraConstrained"));
4333 			is >> cameraConstrained;
4334 			levelSF->SetAttribute("cameraConstrained", cameraConstrained);
4335 			std::ostringstream os;
4336 			os << "cameraConstrained: " << cameraConstrained;
4337 			debugLog(os.str());
4338 		}
4339 		if (level->Attribute("maxZoom"))
4340 		{
4341 			maxZoom = atof(level->Attribute("maxZoom"));
4342 			std::ostringstream os;
4343 			os << maxZoom;
4344 			levelSF->SetAttribute("maxZoom", os.str().c_str());
4345 		}
4346 		if (level->Attribute("natureForm"))
4347 		{
4348 			sceneNatureForm = level->Attribute("natureForm");
4349 			levelSF->SetAttribute("natureForm", sceneNatureForm.c_str());
4350 		}
4351 		if (level->Attribute("bg"))
4352 		{
4353 			std::string tex = std::string(level->Attribute("bg"));
4354 			if (!tex.empty())
4355 			{
4356 				/*
4357 				if (tex.find('.') == std::string::npos)
4358 					bg->setTexture(tex+"");
4359 				else
4360 					bg->setTexture(tex);
4361 				*/
4362 
4363 				bg->setTexture(tex);
4364 				bg->setWidthHeight(900,600);
4365 				levelSF->SetAttribute("bg", tex.c_str());
4366 			}
4367 			else
4368 			{
4369 				bg->alpha = 0;
4370 			}
4371 		}
4372 		else
4373 		{
4374 			bg->alpha = 0;
4375 			//grad->alpha =0;
4376 		}
4377 		gradTop = gradBtm = Vector(0,0,0);
4378 		if (level->Attribute("gradient"))
4379 		{
4380 			if (level->Attribute("gradTop"))
4381 			{
4382 				SimpleIStringStream is(level->Attribute("gradTop"));
4383 				is >> gradTop.x >> gradTop.y >> gradTop.z;
4384 				levelSF->SetAttribute("gradTop", level->Attribute("gradTop"));
4385 			}
4386 			if (level->Attribute("gradBtm"))
4387 			{
4388 				SimpleIStringStream is(level->Attribute("gradBtm"));
4389 				is >> gradBtm.x >> gradBtm.y >> gradBtm.z;
4390 				levelSF->SetAttribute("gradBtm", level->Attribute("gradBtm"));
4391 			}
4392 			createGradient();
4393 			levelSF->SetAttribute("gradient", 1);
4394 		}
4395 
4396 		if (level->Attribute("parallax"))
4397 		{
4398 			SimpleIStringStream is(level->Attribute("parallax"));
4399 			float x,y,z,r,g,b;
4400 			is >> x >> y >> z >> r >> g >> b;
4401 			RenderObjectLayer *l = 0;
4402 			l = &dsq->renderObjectLayers[LR_ELEMENTS10];
4403 			l->followCamera = x;
4404 			l = &dsq->renderObjectLayers[LR_ELEMENTS11];
4405 			l->followCamera = y;
4406 			l = &dsq->renderObjectLayers[LR_ENTITIES_MINUS4_PLACEHOLDER];
4407 			l->followCamera = y;
4408 			l = &dsq->renderObjectLayers[LR_ENTITIES_MINUS4];
4409 			l->followCamera = y;
4410 			l = &dsq->renderObjectLayers[LR_ELEMENTS12];
4411 			l->followCamera = z;
4412 			l = &dsq->renderObjectLayers[LR_ELEMENTS14];
4413 			l->followCamera = r;
4414 			l = &dsq->renderObjectLayers[LR_ELEMENTS15];
4415 			l->followCamera = g;
4416 			l = &dsq->renderObjectLayers[LR_ELEMENTS16];
4417 			l->followCamera = b;
4418 			levelSF->SetAttribute("parallax", level->Attribute("parallax"));
4419 		}
4420 
4421 		if (level->Attribute("parallaxLock"))
4422 		{
4423 			int x, y, z, r, g, b;
4424 			SimpleIStringStream is(level->Attribute("parallaxLock"));
4425 			is >> x >> y >> z >> r >> g >> b;
4426 
4427 			RenderObjectLayer *l = 0;
4428 			l = &dsq->renderObjectLayers[LR_ELEMENTS10];
4429 			l->followCameraLock = x;
4430 			l = &dsq->renderObjectLayers[LR_ELEMENTS11];
4431 			l->followCameraLock = y;
4432 			l = &dsq->renderObjectLayers[LR_ELEMENTS12];
4433 			l->followCameraLock = z;
4434 			l = &dsq->renderObjectLayers[LR_ELEMENTS14];
4435 			l->followCameraLock = r;
4436 			l = &dsq->renderObjectLayers[LR_ELEMENTS15];
4437 			l->followCameraLock = g;
4438 			l = &dsq->renderObjectLayers[LR_ELEMENTS16];
4439 			l->followCameraLock = b;
4440 
4441 			levelSF->SetAttribute("parallaxLock", level->Attribute("parallaxLock"));
4442 		}
4443 
4444 		if (level->Attribute("bg2"))
4445 		{
4446 
4447 			std::string tex = std::string(level->Attribute("bg2"));
4448 			if (!tex.empty())
4449 			{
4450 				/*
4451 				if (tex.find('.') == std::string::npos)
4452 					bg2->setTexture(tex+"");
4453 				else
4454 					bg2->setTexture(tex);
4455 				*/
4456 				bg2->setTexture(tex);
4457 				bg2->setWidthHeight(900,600);
4458 				levelSF->SetAttribute("bg2", tex.c_str());
4459 
4460 			}
4461 			else
4462 				bg2->alpha = 0;
4463 			//createGradient();
4464 
4465 			bg2->alpha = 0;
4466 			bg->alpha = 0;
4467 		}
4468 		else
4469 		{
4470 			bg2->alpha = 0;
4471 			//grad->alpha =0;
4472 		}
4473 
4474 		if (level->Attribute("backdrop"))
4475 		{
4476 			std::string backdrop = level->Attribute("backdrop");
4477 			backdropQuad = new Quad;
4478 			backdropQuad->setTexture(backdrop);
4479 			backdropQuad->blendEnabled = false;
4480 
4481 			if (level->Attribute("bd-x") && level->Attribute("bd-y"))
4482 			{
4483 				int x = atoi(level->Attribute("bd-x"));
4484 				int y = atoi(level->Attribute("bd-y"));
4485 				backdropQuad->position = Vector(x,y);
4486 				levelSF->SetAttribute("bd-x", x);
4487 				levelSF->SetAttribute("bd-y", y);
4488 			}
4489 			if (level->Attribute("bd-w") && level->Attribute("bd-h"))
4490 			{
4491 				int w = atoi(level->Attribute("bd-w"));
4492 				int h = atoi(level->Attribute("bd-h"));
4493 				backdropQuad->setWidthHeight(w, h);
4494 				levelSF->SetAttribute("bd-w", w);
4495 				levelSF->SetAttribute("bd-h", h);
4496 			}
4497 			backdropQuad->toggleCull(false);
4498 			//backdropQuad->followCamera = 1;
4499 			addRenderObject(backdropQuad, LR_SCENEBACKGROUNDIMAGE);
4500 
4501 			// upper left justify
4502 			backdropQuad->offset =
4503 				Vector((backdropQuad->getWidth()*backdropQuad->scale.x)/2.0f,
4504 				(backdropQuad->getHeight()*backdropQuad->scale.y)/2.0f);
4505 			// save
4506 			levelSF->SetAttribute("backdrop", backdrop.c_str());
4507 			//backdrop="cavebg" bd-w="2400" bd-h="2400"
4508 		}
4509 		musicToPlay = "";
4510 		if (level->Attribute("music"))
4511 		{
4512 			setMusicToPlay(level->Attribute("music"));
4513 			saveMusic = level->Attribute("music");
4514 			levelSF->SetAttribute("music", level->Attribute("music"));
4515 			/*
4516 			// if using SDL_Mixer
4517 			if (!core->sound->isPlayingMusic(musicToPlay))
4518 			{
4519 				core->sound->fadeMusic(SFT_OUT, 1);
4520 			}
4521 			*/
4522 		}
4523 		if (level->Attribute("sceneColor"))
4524 		{
4525 			SimpleIStringStream in(level->Attribute("sceneColor"));
4526 			in >> sceneColor.x >> sceneColor.y >> sceneColor.z;
4527 			levelSF->SetAttribute("sceneColor", level->Attribute("sceneColor"));
4528 		}
4529 
4530 		saveFile->InsertEndChild(levelSF);
4531 	}
4532 	else
4533 		return false;
4534 
4535 	XMLElement *obs = doc.FirstChildElement("Obs");
4536 	if (obs)
4537 	{
4538 		int tx, ty, len;
4539 		SimpleIStringStream is(obs->Attribute("d"));
4540 		while (is >> tx)
4541 		{
4542 			is >> ty >> len;
4543 			addObsRow(tx, ty, len);
4544 		}
4545 		addProgress();
4546 	}
4547 
4548 	XMLElement *pathXml = doc.FirstChildElement("Path");
4549 	while (pathXml)
4550 	{
4551 		Path *path = new Path;
4552 		path->name = pathXml->Attribute("name");
4553 		stringToLower(path->name);
4554 		/*
4555 		if (pathXml->Attribute("active"))
4556 		{
4557 			path.active = atoi(pathXml->Attribute("active"));
4558 		}
4559 		*/
4560 		XMLElement *nodeXml = pathXml->FirstChildElement("Node");
4561 		while (nodeXml)
4562 		{
4563 			PathNode node;
4564 			SimpleIStringStream is(nodeXml->Attribute("pos"));
4565 			is >> node.position.x >> node.position.y;
4566 
4567 			if (nodeXml->Attribute("ms"))
4568 			{
4569 				node.maxSpeed = atoi(nodeXml->Attribute("ms"));
4570 			}
4571 
4572 			if (nodeXml->Attribute("rect"))
4573 			{
4574 				SimpleIStringStream is(nodeXml->Attribute("rect"));
4575 				int w,h;
4576 				is >> w >> h;
4577 				path->rect.setWidth(w);
4578 				path->rect.setHeight(h);
4579 			}
4580 
4581 			if (nodeXml->Attribute("shape"))
4582 			{
4583 				path->pathShape = (PathShape)atoi(nodeXml->Attribute("shape"));
4584 			}
4585 
4586 			path->nodes.push_back(node);
4587 			nodeXml = nodeXml->NextSiblingElement("Node");
4588 		}
4589 		path->refreshScript();
4590 		addPath(path);
4591 		addProgress();
4592 		pathXml = pathXml->NextSiblingElement("Path");
4593 	}
4594 
4595 	XMLElement *quad = doc.FirstChildElement("Quad");
4596 	while (quad)
4597 	{
4598 		XMLElement *qSF = saveFile->NewElement("Quad");
4599 		int x=0, y=0, z=0;
4600 		int w=0,h=0;
4601 		bool cull=true;
4602 		bool solid = false;
4603 		std::string justify;
4604 		std::string tex;
4605 		qSF->SetAttribute("x", x = atoi(quad->Attribute("x")));
4606 		qSF->SetAttribute("y", y = atoi(quad->Attribute("y")));
4607 		//qSF->SetAttribute("z", z = atoi(quad->Attribute("z")));
4608 		qSF->SetAttribute("w", w = atoi(quad->Attribute("w")));
4609 		qSF->SetAttribute("h", h = atoi(quad->Attribute("h")));
4610 		qSF->SetAttribute("tex", (tex = (quad->Attribute("tex"))).c_str());
4611 		qSF->SetAttribute("cull", cull = atoi(quad->Attribute("cull")));
4612 		qSF->SetAttribute("justify", (justify = (quad->Attribute("justify"))).c_str());
4613 
4614 		if (quad->Attribute("solid"))
4615 			qSF->SetAttribute("solid", solid = atoi(quad->Attribute("solid")));
4616 
4617 		Quad *q = new Quad;
4618 		q->position = Vector(x,y,z);
4619 		/*
4620 		if (solid)
4621 			Texture::pngLoadHaloFix = false;
4622 		*/
4623 		q->setTexture(tex);
4624 		/*
4625 		if (solid)
4626 			Texture::pngLoadHaloFix = true;
4627 		*/
4628 		q->toggleCull(cull);
4629 		q->setWidthHeight(w, h);
4630 
4631 		if (justify == "upperLeft")
4632 		{
4633 			q->offset = Vector((q->getWidth()*q->scale.x)/2.0f, (q->getHeight()*q->scale.y)/2.0f);
4634 		}
4635 		addRenderObject(q, LR_BACKGROUND);
4636 
4637 		saveFile->InsertEndChild(qSF);
4638 
4639 		quad = quad->NextSiblingElement("Quad");
4640 	}
4641 
4642 	XMLElement *floater = doc.FirstChildElement("Floater");
4643 	while(floater)
4644 	{
4645 		XMLElement *nSF = doc.NewElement("Floater");
4646 		if (!floater->Attribute("boxW") || !floater->Attribute("boxH"))
4647 		{
4648 			errorLog ("no boxW/boxH");
4649 			break;
4650 		}
4651 		int boxW, boxH, x, y, fx, fy;
4652 		nSF->SetAttribute("boxW", boxW = atoi(floater->Attribute("boxW")));
4653 		nSF->SetAttribute("boxH", boxH = atoi(floater->Attribute("boxH")));
4654 		nSF->SetAttribute("tex", floater->Attribute("tex"));
4655 		nSF->SetAttribute("x", x = atoi(floater->Attribute("x")));
4656 		nSF->SetAttribute("y", y = atoi(floater->Attribute("y")));
4657 		nSF->SetAttribute("fx", fx = atoi(floater->Attribute("fx")));
4658 		nSF->SetAttribute("fy", fy = atoi(floater->Attribute("fy")));
4659 
4660 		/*
4661 		Floater *f = new Floater(Vector(x,y), Vector(fx, fy), boxW, boxH, tex);
4662 		{
4663 		}
4664 		addRenderObject(f, LR_BACKGROUND);
4665 		saveFile->InsertEndChild(nSF);
4666 		*/
4667 		floater = floater->NextSiblingElement("Floater");
4668 
4669 	}
4670 
4671 	/*
4672 	XMLElement *breakable = doc.FirstChildElement("Breakable");
4673 	while(breakable)
4674 	{
4675 		XMLElement *nSF = doc.NewElement("Breakable");
4676 		if (!breakable->Attribute("boxW") || !breakable->Attribute("boxH"))
4677 		{
4678 			errorLog ("Breakable error.. no boxW/boxH");
4679 			break;
4680 		}
4681 		int boxW, boxH;
4682 		std::string tex;
4683 		nSF->SetAttribute("boxW", boxW = atoi(breakable->Attribute("boxW")));
4684 		nSF->SetAttribute("boxH", boxH = atoi(breakable->Attribute("boxH")));
4685 		tex = breakable->Attribute("tex");
4686 		nSF->SetAttribute("tex", tex);
4687 		Breakable *n = new Breakable(boxW, boxH, tex);
4688 		{
4689 			nSF->SetAttribute("x", n->position.x = atoi(breakable->Attribute("x")));
4690 			nSF->SetAttribute("y", n->position.y = atoi(breakable->Attribute("y")));
4691 			int w=0, h=0;
4692 			if (breakable->Attribute("w"))
4693 				nSF->SetAttribute("w", w = atoi(breakable->Attribute("w")));
4694 			if (breakable->Attribute("h"))
4695 				nSF->SetAttribute("h", h= atoi(breakable->Attribute("h")));
4696 			if (w != 0 && h != 0)
4697 			{
4698 				n->setWidthHeight(w, h);
4699 			}
4700 		}
4701 		addRenderObject(n, LR_BACKGROUND);
4702 		saveFile->InsertEndChild(nSF);
4703 		breakable = breakable->NextSiblingElement("Breakable");
4704 	}
4705 	*/
4706 
4707 	XMLElement *warpArea = doc.FirstChildElement("WarpArea");
4708 	while(warpArea)
4709 	{
4710 		XMLElement *waSF = doc.NewElement("WarpArea");
4711 		WarpArea a;
4712 		waSF->SetAttribute("x", a.position.x = atoi(warpArea->Attribute("x")));
4713 		waSF->SetAttribute("y", a.position.y = atoi(warpArea->Attribute("y")));
4714 		if (warpArea->Attribute("radius"))
4715 			waSF->SetAttribute("radius", a.radius = atoi(warpArea->Attribute("radius")));
4716 		bool isRect = false;
4717 		if (warpArea->Attribute("w"))
4718 		{
4719 			isRect = true;
4720 			waSF->SetAttribute("w", a.w = atoi(warpArea->Attribute("w")));
4721 			waSF->SetAttribute("h", a.h = atoi(warpArea->Attribute("h")));
4722 		}
4723 		if (warpArea->Attribute("g"))
4724 		{
4725 			waSF->SetAttribute("g", a.generated = atoi(warpArea->Attribute("g")));
4726 		}
4727 		std::string sceneString = warpArea->Attribute("scene");
4728 		waSF->SetAttribute("scene", sceneString.c_str());
4729 		/*
4730 		waSF->SetAttribute("ax", a.avatarPosition.x = atoi(warpArea->Attribute("ax")));
4731 		waSF->SetAttribute("ay", a.avatarPosition.y = atoi(warpArea->Attribute("ay")));
4732 		*/
4733 
4734 		SimpleIStringStream is(sceneString);
4735 		std::string sceneName, warpAreaType, side;
4736 		is >> sceneName >> warpAreaType >> a.spawnOffset.x >> a.spawnOffset.y;
4737 		a.spawnOffset.normalize2D();
4738 		a.sceneName = sceneName;
4739 		a.warpAreaType = warpAreaType;
4740 		//a.side = side;
4741 		// saveFile->InsertEndChild(waSF);
4742 
4743 		bool add = true;
4744 		std::string flagCheck;
4745 		if (warpArea->Attribute("flagCheck"))
4746 		{
4747 			flagCheck = warpArea->Attribute("flagCheck");
4748 			add = doFlagCheck(flagCheck);
4749 		}
4750 		if (add)
4751 			warpAreas.push_back(a);
4752 
4753 		if (a.generated)
4754 		{
4755 			setWarpAreaSceneName(a);
4756 		}
4757 
4758 		warpArea = warpArea->NextSiblingElement("WarpArea");
4759 	}
4760 
4761 	XMLElement *schoolFish = doc.FirstChildElement("SchoolFish");
4762 	while(schoolFish)
4763 	{
4764 		int num = atoi(schoolFish->Attribute("num"));
4765 		int x, y;
4766 		int id;
4767 		x = atoi(schoolFish->Attribute("x"));
4768 		y = atoi(schoolFish->Attribute("y"));
4769 		id = atoi(schoolFish->Attribute("id"));
4770 		std::string gfx, texture="flock-0001";
4771 		if (schoolFish->Attribute("gfx"))
4772 		{
4773 			gfx = schoolFish->Attribute("gfx");
4774 			texture = gfx;
4775 			/*
4776 			std::ostringstream os;
4777 			os << "flock-" << gfx << "";
4778 			texture = os.str();
4779 			*/
4780 		}
4781 		int layer = 0;
4782 		if (schoolFish->Attribute("layer"))
4783 		{
4784 			layer = atoi(schoolFish->Attribute("layer"));
4785 		}
4786 
4787 		float size = 1;
4788 		if (schoolFish->Attribute("size"))
4789 		{
4790 			SimpleIStringStream is(schoolFish->Attribute("size"));
4791 			is >> size;
4792 		}
4793 
4794 		int maxSpeed = 0;
4795 		if (schoolFish->Attribute("maxSpeed"))
4796 			maxSpeed = atoi(schoolFish->Attribute("maxSpeed"));
4797 
4798 		int range = 0;
4799 		if (schoolFish->Attribute("range"))
4800 			range = atoi(schoolFish->Attribute("range"));
4801 
4802 		for (int i = 0; i < num; i++)
4803 		{
4804 			SchoolFish *s = new SchoolFish(texture);
4805 			{
4806 				s->position = Vector(x+i*5,y+i*5);
4807 				s->startPos = s->position;
4808 				s->addToFlock(id);
4809 				if (range != 0)
4810 					s->range = range;
4811 				if (maxSpeed != 0)
4812 					s->setMaxSpeed(maxSpeed);
4813 
4814 				std::ostringstream os;
4815 				os << "adding schoolfish (" << s->position.x << ", " << s->position.y << ")";
4816 				debugLog(os.str());
4817 			}
4818 			if (layer == -3)
4819 			{
4820 				addRenderObject(s, LR_ELEMENTS11);
4821 			}
4822 			else
4823 			{
4824 				if (chance(50))
4825 					addRenderObject(s, LR_ENTITIES2);
4826 				else
4827 					addRenderObject(s, LR_ENTITIES);
4828 			}
4829 
4830 			/*if (layer == 1)
4831 			{
4832 				addRenderObject(s, LR_ENTITIES);
4833 			}
4834 			else
4835 			{
4836 				// school fish layer hack
4837 				// because we want all fish on top dammit
4838 				//addRenderObject(s, LR_ENTITIES2);
4839 
4840 				// or...  not?
4841 				//hrm.. why not?
4842 				if (chance(50))
4843 					addRenderObject(s, LR_ENTITIES2);
4844 				else
4845 					addRenderObject(s, LR_ENTITIES);
4846 				//s->setOverrideRenderPass(4);
4847 			}
4848 			*/
4849 			s->applyLayer(layer);
4850 
4851 			s->scale *= size;
4852 			//s->update(0.033);
4853 
4854 		}
4855 
4856 		schoolFish = schoolFish->NextSiblingElement("SchoolFish");
4857 
4858 		XMLElement *newSF = saveFile->NewElement("SchoolFish");
4859 		newSF->SetAttribute("x", x);
4860 		newSF->SetAttribute("y", y);
4861 		newSF->SetAttribute("id", id);
4862 		newSF->SetAttribute("num", num);
4863 
4864 		if (range != 0)
4865 			newSF->SetAttribute("range", range);
4866 		if (maxSpeed != 0)
4867 			newSF->SetAttribute("maxSpeed", maxSpeed);
4868 		if (layer != 0)
4869 			newSF->SetAttribute("layer", layer);
4870 		if (!gfx.empty())
4871 			newSF->SetAttribute("gfx", gfx.c_str());
4872 		if (size != 1)
4873 			newSF->SetAttribute("size", size);
4874 
4875 		saveFile->InsertEndChild(newSF);
4876 	}
4877 	/*
4878 	XMLElement *boxElement = doc.FirstChildElement("BoxElement");
4879 	while (boxElement)
4880 	{
4881 		BoxElement *b = new BoxElement(atoi(boxElement->Attribute("w")), atoi(boxElement->Attribute("h")));
4882 		b->position = Vector(atoi(boxElement->Attribute("x")), atoi(boxElement->Attribute("y")));
4883 		addRenderObject(b, LR_BLACKGROUND);
4884 		b->position.z = boxElementZ;
4885 		dsq->addElement(b);
4886 		boxElement = boxElement->NextSiblingElement("BoxElement");
4887 	}
4888 	*/
4889 	std::vector<Element*> loadedElements;
4890 	loadedElements.reserve(200);
4891 	XMLElement *simpleElements = doc.FirstChildElement("SE");
4892 	while (simpleElements)
4893 	{
4894 		int idx, x, y, rot;
4895 		float sz,sz2;
4896 		loadedElements.clear();
4897 		if (simpleElements->Attribute("d"))
4898 		{
4899 			SimpleIStringStream is(simpleElements->Attribute("d"));
4900 			while (is >> idx)
4901 			{
4902 				is >> x >> y >> rot;
4903 				Element *e = createElement(idx, Vector(x,y), 4);
4904 				e->rotation.z = rot;
4905 				loadedElements.push_back(e);
4906 			}
4907 		}
4908 		if (simpleElements->Attribute("e"))
4909 		{
4910 			SimpleIStringStream is2(simpleElements->Attribute("e"));
4911 			int l = atoi(simpleElements->Attribute("l"));
4912 			while(is2 >> idx)
4913 			{
4914 				is2 >> x >> y >> rot;
4915 				Element *e = createElement(idx, Vector(x,y), l);
4916 				e->rotation.z = rot;
4917 				loadedElements.push_back(e);
4918 			}
4919 		}
4920 		if (simpleElements->Attribute("f"))
4921 		{
4922 			SimpleIStringStream is2(simpleElements->Attribute("f"));
4923 			int l = atoi(simpleElements->Attribute("l"));
4924 			while(is2 >> idx)
4925 			{
4926 				is2 >> x >> y >> rot >> sz;
4927 				Element *e = createElement(idx, Vector(x,y), l);
4928 				e->scale = Vector(sz,sz);
4929 				e->rotation.z = rot;
4930 				loadedElements.push_back(e);
4931 			}
4932 		}
4933 		if (simpleElements->Attribute("g"))
4934 		{
4935 			SimpleIStringStream is2(simpleElements->Attribute("g"));
4936 			int l = atoi(simpleElements->Attribute("l"));
4937 			while(is2 >> idx)
4938 			{
4939 				int fh, fv;
4940 				is2 >> x >> y >> rot >> sz >> fh >> fv;
4941 				Element *e = createElement(idx, Vector(x,y), l);
4942 				if (fh)
4943 					e->flipHorizontal();
4944 				if (fv)
4945 					e->flipVertical();
4946 				e->scale = Vector(sz,sz);
4947 				e->rotation.z = rot;
4948 				loadedElements.push_back(e);
4949 			}
4950 		}
4951 		if (simpleElements->Attribute("h"))
4952 		{
4953 			SimpleIStringStream is2(simpleElements->Attribute("h"));
4954 			int l = atoi(simpleElements->Attribute("l"));
4955 			while(is2 >> idx)
4956 			{
4957 				int fh, fv;
4958 				int flags;
4959 				is2 >> x >> y >> rot >> sz >> fh >> fv >> flags;
4960 				Element *e = createElement(idx, Vector(x,y), l);
4961 				e->elementFlag = (ElementFlag)flags;
4962 				if (e->elementFlag >= EF_MAX || e->elementFlag < EF_NONE)
4963 					e->elementFlag = EF_NONE;
4964 				if (fh)
4965 					e->flipHorizontal();
4966 				if (fv)
4967 					e->flipVertical();
4968 				e->scale = Vector(sz,sz);
4969 				e->rotation.z = rot;
4970 				loadedElements.push_back(e);
4971 			}
4972 		}
4973 		if (simpleElements->Attribute("i"))
4974 		{
4975 			SimpleIStringStream is2(simpleElements->Attribute("i"));
4976 			int l = atoi(simpleElements->Attribute("l"));
4977 			while(is2 >> idx)
4978 			{
4979 				int fh, fv;
4980 				int flags;
4981 				int efxIdx;
4982 				is2 >> x >> y >> rot >> sz >> fh >> fv >> flags >> efxIdx;
4983 				if (sz < MIN_SIZE)
4984 					sz = MIN_SIZE;
4985 				Element *e = createElement(idx, Vector(x,y), l);
4986 				e->elementFlag = (ElementFlag)flags;
4987 				if (fh)
4988 					e->flipHorizontal();
4989 				if (fv)
4990 					e->flipVertical();
4991 
4992 				e->scale = Vector(sz,sz);
4993 				e->rotation.z = rot;
4994 				e->setElementEffectByIndex(efxIdx);
4995 				loadedElements.push_back(e);
4996 			}
4997 		}
4998 		if (simpleElements->Attribute("j"))
4999 		{
5000 			SimpleIStringStream is2(simpleElements->Attribute("j"));
5001 			int l = atoi(simpleElements->Attribute("l"));
5002 			while(is2 >> idx)
5003 			{
5004 				int fh, fv;
5005 				int flags;
5006 				int efxIdx;
5007 				int repeat;
5008 				is2 >> x >> y >> rot >> sz >> fh >> fv >> flags >> efxIdx >> repeat;
5009 				if (sz < MIN_SIZE)
5010 					sz = MIN_SIZE;
5011 				Element *e = createElement(idx, Vector(x,y), l);
5012 				e->elementFlag = (ElementFlag)flags;
5013 				if (fh)
5014 					e->flipHorizontal();
5015 				if (fv)
5016 					e->flipVertical();
5017 
5018 				e->scale = Vector(sz,sz);
5019 				e->rotation.z = rot;
5020 				e->setElementEffectByIndex(efxIdx);
5021 				if (repeat)
5022 					e->repeatTextureToFill(true);
5023 				loadedElements.push_back(e);
5024 			}
5025 		}
5026 		if (simpleElements->Attribute("k"))
5027 		{
5028 			SimpleIStringStream is2(simpleElements->Attribute("k"));
5029 			int l = atoi(simpleElements->Attribute("l"));
5030 			int c = 0;
5031 			while(is2 >> idx)
5032 			{
5033 				int fh, fv;
5034 				int flags;
5035 				int efxIdx;
5036 				int repeat;
5037 				is2 >> x >> y >> rot >> sz >> sz2 >> fh >> fv >> flags >> efxIdx >> repeat;
5038 				if (sz < MIN_SIZE)
5039 					sz = MIN_SIZE;
5040 				if (sz2 < MIN_SIZE)
5041 					sz2 = MIN_SIZE;
5042 				Element *e = createElement(idx, Vector(x,y), l);
5043 				e->elementFlag = (ElementFlag)flags;
5044 				if (fh)
5045 					e->flipHorizontal();
5046 				if (fv)
5047 					e->flipVertical();
5048 
5049 				e->scale = Vector(sz,sz2);
5050 				e->rotation.z = rot;
5051 				e->setElementEffectByIndex(efxIdx);
5052 				if (repeat)
5053 					e->repeatTextureToFill(true);
5054 
5055 				c++;
5056 				if (c> 100)
5057 				{
5058 					c=0;
5059 					addProgress();
5060 				}
5061 
5062 				loadedElements.push_back(e);
5063 			}
5064 		}
5065 		if (simpleElements->Attribute("repeatScale"))
5066 		{
5067 			SimpleIStringStream is2(simpleElements->Attribute("repeatScale"));
5068 			for(size_t i = 0; i < loadedElements.size(); ++i)
5069 			{
5070 				Element *e = loadedElements[i];
5071 				if(e->isRepeatingTextureToFill())
5072 				{
5073 					float repeatScaleX = 1, repeatScaleY = 1;
5074 					if(!(is2 >> repeatScaleX >> repeatScaleY))
5075 						break;
5076 					e->repeatToFillScale.x = repeatScaleX;
5077 					e->repeatToFillScale.y = repeatScaleY;
5078 					e->refreshRepeatTextureToFill();
5079 				}
5080 			}
5081 		}
5082 		simpleElements = simpleElements->NextSiblingElement("SE");
5083 	}
5084 
5085 	XMLElement *element = doc.FirstChildElement("Element");
5086 	while (element)
5087 	{
5088 		if (element->Attribute("idx"))
5089 		{
5090 			int x = atoi(element->Attribute("x"));
5091 			int y = atoi(element->Attribute("y"));
5092 			int idx = atoi(element->Attribute("idx"));
5093 			int layer=LR_ELEMENTS5;
5094 			float rot =0;
5095 			bool flipH = false, flipV = false;
5096 			if (element->Attribute("flipH"))
5097 				flipH = atoi(element->Attribute("flipH"));
5098 			if (element->Attribute("flipV"))
5099 				flipV = atoi(element->Attribute("flipV"));
5100 
5101 			if (element->Attribute("rot"))
5102 				rot = atof(element->Attribute("rot"));
5103 
5104 			if (element->Attribute("lyr"))
5105 				layer = atoi(element->Attribute("lyr"));
5106 
5107 
5108 			if (idx != -1)
5109 			{
5110 				Element *e = createElement(idx, Vector(x,y), layer);
5111 				e->rotation.z = rot;
5112 				if (flipH)
5113 					e->flipHorizontal();
5114 				if (flipV)
5115 					e->flipVertical();
5116 
5117 				if (element->Attribute("sz"))
5118 				{
5119 					SimpleIStringStream is(element->Attribute("sz"));
5120 					is >> e->scale.x >> e->scale.y;
5121 				}
5122 			}
5123 
5124 
5125 		}
5126 		element = element->NextSiblingElement("Element");
5127 	}
5128 
5129 	this->reconstructGrid(true);
5130 
5131 	/*
5132 	XMLElement *enemyNode = doc.FirstChildElement("Enemy");
5133 	while(enemyNode)
5134 	{
5135 		Vector pos;
5136 		pos.x = atoi(enemyNode->Attribute("x"));
5137 		pos.y = atoi(enemyNode->Attribute("y"));
5138 
5139 		std::string type = enemyNode->Attribute("type");
5140 
5141 		std::string flagCheck;
5142 		if (enemyNode->Attribute("flagCheck"))
5143 		{
5144 			flagCheck = enemyNode->Attribute("flagCheck");
5145 		}
5146 		if (doFlagCheck(flagCheck))
5147 			Entity *e = createEnemy(type, pos, true, enemyNode, flagCheck, -1);
5148 
5149 		enemyNode = enemyNode->NextSiblingElement("Enemy");
5150 	}
5151 	*/
5152 	XMLElement *entitiesNode = doc.FirstChildElement("Entities");
5153 	while(entitiesNode)
5154 	{
5155 		if (entitiesNode->Attribute("j"))
5156 		{
5157 			SimpleIStringStream is(entitiesNode->Attribute("j"));
5158 			int idx, x, y, rot, groupID, id;
5159 			std::string name;
5160 			while (is >> idx)
5161 			{
5162 				name="";
5163 				if (idx == -1)
5164 					is >> name;
5165 				is >> x >> y >> rot >> groupID >> id;
5166 
5167 				if (!name.empty())
5168 					dsq->game->createEntity(name, id, Vector(x,y), rot, true, "", ET_ENEMY);
5169 				else
5170 					dsq->game->createEntity(idx, id, Vector(x,y), rot, true, "", ET_ENEMY);
5171 			}
5172 		}
5173 		entitiesNode = entitiesNode->NextSiblingElement("Entities");
5174 	}
5175 	//assignEntitiesUniqueIDs();
5176 	//initEntities();
5177 	FOR_ENTITIES(i)
5178 	{
5179 		Entity *e = *i;
5180 		e->onSceneFlipped();
5181 	}
5182 	this->reconstructGrid(true);
5183 	rebuildElementUpdateList();
5184 	setElementLayerFlags();
5185 
5186 	// HACK: Don't try to optimize the barrier layer in Mithalas Cathedral
5187 	// since elements are turned off dynamically.
5188 	if (nocasecmp(scene, "cathedral02") == 0)
5189 		dsq->getRenderObjectLayer(LR_ELEMENTS3)->setOptimizeStatic(false);
5190 
5191 	findMaxCameraValues();
5192 
5193 	endProgress();
5194 
5195 	return true;
5196 }
5197 
setMusicToPlay(const std::string & m)5198 void Game::setMusicToPlay(const std::string &m)
5199 {
5200 	musicToPlay = m;
5201 	stringToLower(musicToPlay);
5202 }
5203 
findMaxCameraValues()5204 void Game::findMaxCameraValues()
5205 {
5206 	cameraMin.x = 20;
5207 	cameraMin.y = 20;
5208 	cameraMax.x = -1;
5209 	cameraMax.y = -1;
5210 	int i = 0;
5211 	for (i = 0; i < obsRows.size(); i++)
5212 	{
5213 		ObsRow *r = &obsRows[i];
5214 		TileVector t(r->tx + r->len, r->ty);
5215 		Vector v = t.worldVector();
5216 		if (v.x > cameraMax.x)
5217 		{
5218 			cameraMax.x = v.x;
5219 		}
5220 		if (v.y > cameraMax.y)
5221 		{
5222 			cameraMax.y = v.y;
5223 		}
5224 	}
5225 	/*
5226 	for (i = 0; i < dsq->getNumElements(); i++)
5227 	{
5228 		Element *e = dsq->getElement(i);
5229 		if (e->position.x > cameraMax.x)
5230 			cameraMax.x = e->position.x;
5231 		if (e->position.y > cameraMax.y)
5232 			cameraMax.y = e->position.y;
5233 	}
5234 	*/
5235 	if (backdropQuad)
5236 	{
5237 		if (backdropQuad->getWidth() > cameraMax.x)
5238 		{
5239 			cameraMax.x = backdropQuad->getWidth();
5240 		}
5241 		if (backdropQuad->getHeight() > cameraMax.y)
5242 		{
5243 			cameraMax.y = backdropQuad->getHeight();
5244 		}
5245 	}
5246 }
5247 
setWarpAreaSceneName(WarpArea & warpArea)5248 void Game::setWarpAreaSceneName(WarpArea &warpArea)
5249 {
5250 	InStream in("data/warpAreas.txt");
5251 	std::string color, area1, dir1, area2, dir2;
5252 	std::string line;
5253 	while (std::getline(in, line))
5254 	{
5255 
5256 		std::istringstream is(line);
5257 		is >> color >> area1 >> dir1 >> area2 >> dir2;
5258 		/*
5259 		errorLog (color + " : " + area1 + " : " + dir1 + " : " + area2 + " : " + dir2);
5260 		*/
5261 		if (area2 == dsq->game->sceneName && warpArea.warpAreaType == color)
5262 		{
5263 			area2 = area1;
5264 			dir2 = dir1;
5265 			area1 = dsq->game->sceneName;
5266 		}
5267 		if (area1 == dsq->game->sceneName && warpArea.warpAreaType == color)
5268 		{
5269 			if (dir2=="Left")
5270 				warpArea.spawnOffset = Vector(-1,0);
5271 			else if (dir2=="Right")
5272 				warpArea.spawnOffset = Vector(1,0);
5273 			else if (dir2=="Up")
5274 				warpArea.spawnOffset = Vector(0,-1);
5275 			else if (dir2=="Down")
5276 				warpArea.spawnOffset = Vector(0,1);
5277 			warpArea.sceneName = area2;
5278 			break;
5279 		}
5280 	}
5281 	if (warpArea.sceneName.empty())
5282 	{
5283 		errorLog(warpArea.warpAreaType + " WarpArea for " + dsq->game->sceneName + " not found");
5284 	}
5285 }
5286 
loadScene(std::string scene)5287 bool Game::loadScene(std::string scene)
5288 {
5289 	stringToLower(scene);
5290 
5291 	sceneName = scene;
5292 	if (scene.empty())
5293 	{
5294 		return false;
5295 	}
5296 
5297 #ifdef AQUARIA_DEMO
5298 	int i = 0;
5299 	for (; i < allowedMaps.size(); i++)
5300 	{
5301 		if (allowedMaps[i] == scene)
5302 			break;
5303 	}
5304 	if (i == allowedMaps.size())
5305 	{
5306 		exit_error("Demo version refuses to load this map, sorry.");
5307 	}
5308 #endif
5309 
5310 
5311 	loadingScene = true;
5312 	bool ret = loadSceneXML(scene);
5313 	loadingScene = false;
5314 
5315 	return ret;
5316 
5317 	/*
5318 	std::string fn = ("data/maps/"+scene+".xml");
5319 	if (!exists(fn))
5320 	{
5321 		loadSceneDAT(scene);
5322 		return;
5323 	}
5324 	loadSceneXML(scene);
5325 	*/
5326 
5327 
5328 	/*
5329 
5330 	*/
5331 }
5332 
saveScene(std::string scene)5333 bool Game::saveScene(std::string scene)
5334 {
5335 	if (!this->saveFile)
5336 		return false;
5337 
5338 	std::string fn = getSceneFilename(scene);
5339 
5340 	XMLDocument saveFile;
5341 
5342 	// hackish: Deep-clone XML doc
5343 	{
5344 		XMLPrinter printer;
5345 		this->saveFile->Print(&printer);
5346 
5347 		XMLError xmlerr = saveFile.Parse(printer.CStr(), printer.CStrSize());
5348 		if(xmlerr != XML_SUCCESS)
5349 		{
5350 			std::ostringstream os;
5351 			os << "Game::saveScene(): Whoops? Deep cloning level XML failed: Error " << xmlerr;
5352 			errorLog(os.str());
5353 		}
5354 	}
5355 
5356 	XMLElement *level = saveFile.FirstChildElement("Level");
5357 	if(!level)
5358 	{
5359 		level = saveFile.NewElement("Level");
5360 		saveFile.InsertFirstChild(level);
5361 	}
5362 
5363 	if (level)
5364 	{
5365 		level->SetAttribute("waterLevel", dsq->game->saveWaterLevel);
5366 
5367 		if (grad)
5368 		{
5369 			level->SetAttribute("gradient", 1);
5370 
5371 			std::ostringstream os;
5372 			os << gradTop.x << " " << gradTop.y << " " << gradTop.z;
5373 			level->SetAttribute("gradTop", os.str().c_str());
5374 
5375 			std::ostringstream os2;
5376 			os2 << gradBtm.x << " " << gradBtm.y << " " << gradBtm.z;
5377 			level->SetAttribute("gradBtm", os2.str().c_str());
5378 
5379 		}
5380 
5381 		if (!saveMusic.empty())
5382 		{
5383 			level->SetAttribute("music", saveMusic.c_str());
5384 		}
5385 	}
5386 
5387 	/*
5388 	XMLElement *level = doc.NewElement("Level");
5389 	level->SetAttribute("elementTemplatePack", elementTemplatePack);
5390 	if (bg)
5391 	{
5392 		int pos = bg->texture->name.find_last_of('/')+1;
5393 		int pos2 = bg->texture->name.find_last_of('.');
5394 		level->SetAttribute("bg", bg->texture->name.substr(pos, pos2-pos));
5395 		std::ostringstream os;
5396 		os << sceneColor.x << " " << sceneColor.y << " " << sceneColor.z;
5397 		level->SetAttribute("sceneColor", os.str());
5398 	}
5399 	saveFile->InsertEndChild(level);
5400 	*/
5401 
5402 	std::ostringstream obs;
5403 	int i = 0;
5404 	for (i = 0; i < obsRows.size(); i++)
5405 	{
5406 		obs << obsRows[i].tx << " " << obsRows[i].ty << " " << obsRows[i].len << " ";
5407 	}
5408 	XMLElement *obsXml = saveFile.NewElement("Obs");
5409 	obsXml->SetAttribute("d", obs.str().c_str());
5410 	saveFile.InsertEndChild(obsXml);
5411 
5412 
5413 	for (i = 0; i < dsq->game->getNumPaths(); i++)
5414 	{
5415 		XMLElement *pathXml = saveFile.NewElement("Path");
5416 		Path *p = dsq->game->getPath(i);
5417 		pathXml->SetAttribute("name", p->name.c_str());
5418 		//pathXml->SetAttribute("active", p->active);
5419 		for (int n = 0; n < p->nodes.size(); n++)
5420 		{
5421 			XMLElement *nodeXml = saveFile.NewElement("Node");
5422 			std::ostringstream os;
5423 			os << int(p->nodes[n].position.x) << " " << int(p->nodes[n].position.y);
5424 			nodeXml->SetAttribute("pos", os.str().c_str());
5425 			std::ostringstream os2;
5426 			os2 << p->rect.getWidth() << " " << p->rect.getHeight();
5427 			nodeXml->SetAttribute("rect", os2.str().c_str());
5428 			nodeXml->SetAttribute("shape", (int)p->pathShape);
5429 			if (p->nodes[n].maxSpeed != -1)
5430 			{
5431 				nodeXml->SetAttribute("ms", p->nodes[n].maxSpeed);
5432 			}
5433 			pathXml->InsertEndChild(nodeXml);
5434 		}
5435 		saveFile.InsertEndChild(pathXml);
5436 	}
5437 
5438 	for (i = 0; i < dsq->game->warpAreas.size(); i++)
5439 	{
5440 		WarpArea a = dsq->game->warpAreas[i];
5441 		XMLElement *waSF = saveFile.NewElement("WarpArea");
5442 		waSF->SetAttribute("x", a.position.x);
5443 		waSF->SetAttribute("y", a.position.y);
5444 		if (a.radius > 0)
5445 			waSF->SetAttribute("radius", a.radius);
5446 		else if (a.w > 0 && a.h > 0)
5447 		{
5448 			waSF->SetAttribute("w", a.w);
5449 			waSF->SetAttribute("h", a.h);
5450 		}
5451 		if (a.generated)
5452 		{
5453 			waSF->SetAttribute("g", 1);
5454 		}
5455 		std::ostringstream os;
5456 		os << a.sceneName << " " << a.warpAreaType << " " << a.spawnOffset.x << " " << a.spawnOffset.y;
5457 		waSF->SetAttribute("scene", os.str().c_str());
5458 
5459 		saveFile.InsertEndChild(waSF);
5460 	}
5461 
5462 	std::ostringstream simpleElements[LR_MAX];
5463 	std::ostringstream simpleElements_repeatScale[LR_MAX];
5464 
5465 
5466 	for (i = 0; i < dsq->getNumElements(); i++)
5467 	{
5468 		Element *e = dsq->getElement(i);
5469 		std::ostringstream& SE = simpleElements[e->bgLayer];
5470 		SE << e->templateIdx << " "
5471 		   << int(e->position.x) << " "
5472 		   << int(e->position.y) << " "
5473 		   << int(e->rotation.z) << " "
5474 		   << e->scale.x << " "
5475 		   << e->scale.y << " "
5476 		   << int(e->isfh()) << " "
5477 		   << int(e->isfv()) << " "
5478 		   << e->elementFlag << " "
5479 		   << e->getElementEffectIndex()<< " "
5480 		   << e->isRepeatingTextureToFill() << " ";
5481 
5482 		if(e->isRepeatingTextureToFill())
5483 		{
5484 			std::ostringstream& SE_rs = simpleElements_repeatScale[e->bgLayer];
5485 			SE_rs << e->repeatToFillScale.x << " "
5486 			      << e->repeatToFillScale.y << " ";
5487 		}
5488 	}
5489 
5490 	if (dsq->game->entitySaveData.size() > 0)
5491 	{
5492 		XMLElement *entitiesNode = saveFile.NewElement("Entities");
5493 
5494 		std::ostringstream os;
5495 		for (int i = 0; i < dsq->game->entitySaveData.size(); i++)
5496 		{
5497 			EntitySaveData *e = &dsq->game->entitySaveData[i];
5498 			os << e->idx << " ";
5499 
5500 			if (e->idx == -1)
5501 			{
5502 				if (!e->name.empty())
5503 					os << e->name << " ";
5504 				else
5505 					os << "INVALID" << " ";
5506 			}
5507 			// group ID no longer used
5508 			os << e->x << " " << e->y << " " << e->rot << " " << 0 << " " << e->id << " ";
5509 		}
5510 		entitiesNode->SetAttribute("j", os.str().c_str());
5511 		saveFile.InsertEndChild(entitiesNode);
5512 	}
5513 
5514 	for (i = 0; i < LR_MAX; i++)
5515 	{
5516 		std::string s = simpleElements[i].str();
5517 		if (!s.empty())
5518 		{
5519 			XMLElement *simpleElementsXML = saveFile.NewElement("SE");
5520 			simpleElementsXML->SetAttribute("k", s.c_str());
5521 			simpleElementsXML->SetAttribute("l", i);
5522 			std::string repeatScaleStr = simpleElements_repeatScale[i].str();
5523 			if(!repeatScaleStr.empty())
5524 				simpleElementsXML->SetAttribute("repeatScale", repeatScaleStr.c_str());
5525 			saveFile.InsertEndChild(simpleElementsXML);
5526 		}
5527 	}
5528 
5529 	// HACK: fix this later (won't save light shafts)
5530 	/*
5531 	for (Core::RenderObjects::iterator i = core->renderObjects.begin(); i != core->renderObjects.end(); i++)
5532 	{
5533 		LightShaft *l = dynamic_cast<LightShaft*>(*i);
5534 		if (l)
5535 		{
5536 			XMLElement *lightShaft = saveFile.NewElement("LightShaft");
5537 			lightShaft->SetAttribute("x", l->position.x);
5538 			lightShaft->SetAttribute("y", l->position.y);
5539 			std::ostringstream os;
5540 			os << l->getDir().x;
5541 			lightShaft->SetAttribute("dirx", os.str());
5542 			std::ostringstream os2;
5543 			os2 << l->getDir().y;
5544 			lightShaft->SetAttribute("diry", os2.str());
5545 			std::ostringstream os3;
5546 			os3 << l->shaftWidth;
5547 			lightShaft->SetAttribute("w", os3.str());
5548 
5549 			//lightShaft->SetAttribute("dirx", int(l->getDir().x*1000));
5550 			//lightShaft->SetAttribute("diry", int(l->getDir().y*1000));
5551 			saveFile.InsertEndChild(lightShaft);
5552 		}
5553 	}
5554 	*/
5555 
5556 	bool result =  saveFile.SaveFile(fn.c_str()) == XML_SUCCESS;
5557 	if (result)
5558 		debugLog("Successfully saved map: " + fn);
5559 	else
5560 		debugLog("Failed to save map: " + fn);
5561 
5562 	return result;
5563 }
5564 
warpToArea(WarpArea * area)5565 void Game::warpToArea(WarpArea *area)
5566 {
5567 	if (this->miniMapHint.scene == area->sceneName && this->miniMapHint.warpAreaType == area->warpAreaType)
5568 	{
5569 		miniMapHint.clear();
5570 	}
5571 	//positionToAvatar = area->avatarPosition;
5572 	dsq->game->warpAreaType = area->warpAreaType;
5573 	dsq->game->spawnOffset = area->spawnOffset;
5574 	//dsq->game->warpAreaSide = area->;
5575 	dsq->game->transitionToScene(area->sceneName);
5576 }
5577 
createGradient()5578 void Game::createGradient()
5579 {
5580 	if (grad)
5581 	{
5582 		grad->safeKill();
5583 		grad = 0;
5584 	}
5585 	if (!grad)
5586 	{
5587 		grad = new Gradient;
5588 		{
5589 			//grad->makeVertical(Vector(0.6, 0.75, 0.65), Vector(0.4, 0.6, 0.5));
5590 			//grad->makeVertical(Vector(0.6, 0.8, 0.65), Vector(0.1, 0.2, 0.4));
5591 			grad->makeVertical(gradTop, gradBtm);
5592 			grad->autoWidth = AUTO_VIRTUALWIDTH;
5593 			grad->autoHeight = AUTO_VIRTUALHEIGHT;
5594 			//grad->scale = Vector(core->getVirtualWidth(), core->getVirtualHeight());
5595 			grad->position = Vector(400,300,-4);
5596 			grad->followCamera = 1;
5597 			grad->alpha = 1;
5598 			grad->toggleCull(false);
5599 		}
5600 		addRenderObject(grad, LR_BACKDROP);
5601 		if (bg)
5602 			bg->blendEnabled = true;
5603 		if (bg2)
5604 			bg2->blendEnabled = true;
5605 	}
5606 }
5607 
isInGameMenu()5608 bool Game::isInGameMenu()
5609 {
5610 	return inGameMenu;
5611 }
5612 
isValidTarget(Entity * e,Entity * me)5613 bool Game::isValidTarget(Entity *e, Entity *me)
5614 {
5615 	//(e->layer == LR_ENTITIES0 || e->layer == LR_ENTITIES || e->layer == LR_ENTITIES2)
5616 	//&& true
5617 	return (e != me && e->isNormalLayer() && e->isPresent() && e->getEntityType() == ET_ENEMY && e->isAvatarAttackTarget());
5618 }
5619 
updateMiniMapHintPosition()5620 void Game::updateMiniMapHintPosition()
5621 {
5622 	miniMapHintPosition = Vector(0,0,0);
5623 	for (int i = 0; i < warpAreas.size(); i++)
5624 	{
5625 		if (this->sceneName == miniMapHint.scene)
5626 		{
5627 			if (warpAreas[i].warpAreaType == miniMapHint.warpAreaType)
5628 			{
5629 				miniMapHintPosition = warpAreas[i].position;
5630 			}
5631 		}
5632 		else
5633 		{
5634 			if (warpAreas[i].sceneName == miniMapHint.scene)
5635 			{
5636 				miniMapHintPosition = warpAreas[i].position;
5637 			}
5638 		}
5639 	}
5640 }
5641 
createPets()5642 void Game::createPets()
5643 {
5644 	setActivePet(dsq->continuity.getFlag(FLAG_PET_ACTIVE));
5645 }
5646 
setActivePet(int flag)5647 Entity* Game::setActivePet(int flag)
5648 {
5649 	if (currentPet)
5650 	{
5651 		currentPet->safeKill();
5652 		currentPet = 0;
5653 	}
5654 
5655 	dsq->continuity.setFlag(FLAG_PET_ACTIVE, flag);
5656 
5657 	if (flag != 0)
5658 	{
5659 
5660 		int petv = flag - FLAG_PET_NAMESTART;
5661 
5662 		PetData *p = dsq->continuity.getPetData(petv);
5663 		if (p)
5664 		{
5665 			std::string name = p->namePart;
5666 
5667 			Entity *e = createEntity("Pet_" + name, -1, avatar->position, 0, false, "");
5668 			if (e)
5669 			{
5670 				currentPet = e;
5671 				e->setState(Entity::STATE_FOLLOW, -1, true);
5672 				e->postInit();
5673 			}
5674 		}
5675 	}
5676 
5677 	return currentPet;
5678 }
5679 
createLi()5680 void Game::createLi()
5681 {
5682 	int liFlag = dsq->continuity.getFlag(FLAG_LI);
5683 	std::ostringstream os;
5684 	os << "liFlag: " << liFlag;
5685 	debugLog(os.str());
5686 
5687 	if (liFlag == 100)
5688 	{
5689 		debugLog("Creating Li");
5690 		li = createEntity("Li", 0, Vector(0,0), 0, false, "");
5691 		//li->skeletalSprite.animate("idle");
5692 	}
5693 }
5694 
colorTest()5695 void Game::colorTest()
5696 {
5697 	// test element coloring
5698 	// possibly useful for darker maps
5699 	/*
5700 	std::vector<QuadLight> quadLights;
5701 	quadLights.push_back(QuadLight(Vector(400, 300), Vector(1, 0, 0), 2000));
5702 	for (int i = 0; i < dsq->getNumElements(); i++)
5703 	{
5704 		Element *e = dsq->getElement(i);
5705 		//e->color = Vector(rand()%100, rand()%100, rand()%100);
5706 		for (int i = 0; i < quadLights.size(); i++)
5707 		{
5708 			QuadLight *q = &quadLights[i];
5709 			Vector dist = e->position - q->position;
5710 			if (dist.isLength2DIn(q->dist))
5711 			{
5712 				float fract = float(dist.getLength2D())/float(quadLights[i].dist);
5713 				float amb = fract;
5714 				fract = 1.0f - fract;
5715 				e->color = Vector(1,1,1)*amb + q->color*fract;
5716 			}
5717 			else
5718 			{
5719 				e->color = Vector(1,1,0);
5720 			}
5721 		}
5722 		//e->color.normalize2D();
5723 	}
5724 	*/
5725 }
5726 
showImage(const std::string & gfx)5727 void Game::showImage(const std::string &gfx)
5728 {
5729 	if (!image)
5730 	{
5731 		//float t = lua_tonumber(L, 2);
5732 
5733 		dsq->overlay->color = Vector(1,1,1);
5734 		dsq->fade(1, 0.5);
5735 		dsq->watch(0.5);
5736 
5737 		image = new Quad;
5738 		image->setTexture(gfx);
5739 		image->position = Vector(400,300);
5740 		image->setWidthHeight(800, 800);
5741 		image->offset = Vector(0,100);
5742 		image->alpha = 0;
5743 		image->followCamera = 1;
5744 		core->addRenderObject(image, LR_HUD);
5745 
5746 		image->scale = Vector(1,1);
5747 		image->scale.interpolateTo(Vector(1.1, 1.1), 12);
5748 
5749 		image->alpha = 1;
5750 		dsq->fade(0, 0.5);
5751 	}
5752 }
5753 
hideImage()5754 void Game::hideImage()
5755 {
5756 	if (image)
5757 	{
5758 		image->setLife(1);
5759 		image->setDecayRate(1.0f/2.0f);
5760 		image->fadeAlphaWithLife = 1;
5761 	}
5762 
5763 	image = 0;
5764 	dsq->overlay->color = 0;
5765 }
5766 
switchBgLoop(int v)5767 void Game::switchBgLoop(int v)
5768 {
5769 	if (v != lastBgSfxLoop)
5770 	{
5771 		if (dsq->loops.bg != BBGE_AUDIO_NOCHANNEL)
5772 		{
5773 			core->sound->fadeSfx(dsq->loops.bg, SFT_OUT, 0.5);
5774 			dsq->loops.bg = BBGE_AUDIO_NOCHANNEL;
5775 		}
5776 
5777 		switch(v)
5778 		{
5779 		case 0:
5780 			if (!bgSfxLoop.empty())
5781 			{
5782 			    PlaySfx sfx;
5783 			    sfx.name = bgSfxLoop;
5784 			    sfx.vol = bgSfxVol;
5785 			    sfx.loops = -1;
5786 				sfx.priority = 0.8;
5787 				dsq->loops.bg = core->sound->playSfx(sfx);
5788 			}
5789 		break;
5790 		case 1:
5791 			if (!airSfxLoop.empty())
5792 			{
5793 			    PlaySfx sfx;
5794 			    sfx.name = airSfxLoop;
5795 			    sfx.vol = bgSfxVol;
5796 			    sfx.loops = -1;
5797 				sfx.priority = 0.8;
5798 				dsq->loops.bg = core->sound->playSfx(sfx);
5799 			}
5800 		break;
5801 		}
5802 		lastBgSfxLoop = v;
5803 	}
5804 }
5805 
entityDied(Entity * eDead)5806 void Game::entityDied(Entity *eDead)
5807 {
5808 	Entity *e = 0;
5809 	FOR_ENTITIES(i)
5810 	{
5811 		e = *i;
5812 		if (e != eDead && e->isv(EV_ENTITYDIED,1))
5813 		{
5814 			e->entityDied(eDead);
5815 		}
5816 	}
5817 
5818 	dsq->continuity.entityDied(eDead);
5819 }
5820 
postInitEntities()5821 void Game::postInitEntities()
5822 {
5823 	FOR_ENTITIES(i)
5824 	{
5825 		Entity *e = *i;
5826 		if (e)
5827 		{
5828 			e->postInit();
5829 		}
5830 	}
5831 	core->resetTimer();
5832 }
5833 
updateParticlePause()5834 void Game::updateParticlePause()
5835 {
5836 	if (this->isPaused())
5837 	{
5838 		core->particlesPaused = 2;
5839 	}
5840 	else if (this->isWorldPaused())
5841 	{
5842 		core->particlesPaused = 1;
5843 	}
5844 	else
5845 	{
5846 		core->particlesPaused = 0;
5847 	}
5848 }
5849 
game_collideParticle(Vector pos)5850 int game_collideParticle(Vector pos)
5851 {
5852 	bool aboveWaterLine = (pos.y <= dsq->game->waterLevel.x+20);
5853 	bool inWaterBubble = false;
5854 	if (!aboveWaterLine)
5855 	{
5856 		Path *p = dsq->game->getNearestPath(pos, PATH_WATERBUBBLE);
5857 		if (p && p->active)
5858 		{
5859 			if (p->isCoordinateInside(pos))
5860 			{
5861 				inWaterBubble = true;
5862 			}
5863 		}
5864 	}
5865 	if (!inWaterBubble && aboveWaterLine)
5866 	{
5867 		return 1;
5868 	}
5869 
5870 	TileVector t(pos);
5871 	return dsq->game->isObstructed(t);
5872 }
5873 
game_wibbleParticle(Particle * p)5874 void game_wibbleParticle(Particle *p)
5875 {
5876 	/*
5877 	if (dsq->game->avatar->getNotesOpen() > 0 && (p->position - dsq->game->avatar->position).isLength2DIn(256))
5878 	{
5879 		if (!p->offset.isInterpolating())
5880 		{
5881 			p->offset.interpolateTo(Vector(10,0), (8-dsq->game->avatar->getLastNote())/10.0f, -1, 1);
5882 
5883 			//if (dsq->game->avatar->isSinging())
5884 			//{
5885 			//	p->influenceVariable = 1;
5886 			//	p->color.interpolateTo(dsq->getNoteColor(dsq->game->avatar->getLastNote()), 1.0);
5887 			//}
5888 
5889 		}
5890 		else
5891 		{
5892 		}
5893 	}
5894 	else
5895 	{
5896 		p->offset.stop();
5897 
5898 		//if (p->influenceVariable)
5899 		//	p->color.interpolateTo(Vector(1,1,1), 1);
5900 
5901 	}
5902 	*/
5903 }
5904 
rebuildElementUpdateList()5905 void Game::rebuildElementUpdateList()
5906 {
5907 	for (int i = LR_ELEMENTS1; i <= LR_ELEMENTS8; i++)
5908 		dsq->getRenderObjectLayer(i)->update = false;
5909 
5910 	elementUpdateList.clear();
5911 	elementInteractionList.clear();
5912 	for (int i = 0; i < dsq->getNumElements(); i++)
5913 	{
5914 		Element *e = dsq->getElement(i);
5915 		const int eeidx = e->getElementEffectIndex();
5916 		if (eeidx != -1 && e->layer >= LR_ELEMENTS1 && e->layer <= LR_ELEMENTS8)
5917 			elementUpdateList.push_back(e);
5918 		ElementEffect ee = dsq->getElementEffectByIndex(eeidx);
5919 		if(ee.type == EFX_WAVY)
5920 			elementInteractionList.push_back(e);
5921 	}
5922 }
5923 
setElementLayerFlags()5924 void Game::setElementLayerFlags()
5925 {
5926 	for (int i = LR_ELEMENTS1; i <= LR_ELEMENTS16; i++)
5927 	{
5928 		// FIXME: Background SchoolFish get added to ELEMENTS11, so
5929 		// we can't optimize that layer.  (Maybe create a new layer?)
5930 		if (i == LR_ELEMENTS11)
5931 			continue;
5932 
5933 		dsq->getRenderObjectLayer(i)->setOptimizeStatic(!isSceneEditorActive() && dsq->user.video.displaylists);
5934 	}
5935 }
5936 
getTimer(float mod)5937 float Game::getTimer(float mod)
5938 {
5939 	return timer*mod;
5940 }
5941 
getHalf2WayTimer(float mod)5942 float Game::getHalf2WayTimer(float mod)
5943 {
5944 	float t=timer;
5945 	if (t > 0.5f)
5946 		t = 1 - t;
5947 	return timer*2*mod;
5948 }
5949 
getHalfTimer(float mod)5950 float Game::getHalfTimer(float mod)
5951 {
5952 	return halfTimer*mod;
5953 }
5954 
action(int id,int state)5955 void Game::action(int id, int state)
5956 {
5957 	for (int i = 0; i < paths.size(); i++)
5958 	{
5959 		if (paths[i]->catchActions)
5960 		{
5961 			if (!paths[i]->action(id, state))
5962 				break;
5963 		}
5964 	}
5965 
5966 	if(isIgnoreAction((AquariaActions)id))
5967 		return;
5968 
5969 	if (id == ACTION_TOGGLEHELPSCREEN && !state)
5970 	{
5971 		onToggleHelpScreen();
5972 		//toggleHelpScreen(!inHelpScreen);
5973 	}
5974 	if (id == ACTION_ESC && !state)					onPressEscape();
5975 	if (id == ACTION_PRIMARY && !state)				onLeftMouseButton();
5976 	if (id == ACTION_TOGGLEMENU)
5977 	{
5978 		if(state)
5979 			showInGameMenu();
5980 		else
5981 			hideInGameMenu();
5982 	}
5983 	if (id == ACTION_TOGGLEWORLDMAP && !state)
5984 	{
5985 		if (foodMenu)
5986 		{
5987 			recipes->setFocus(true);
5988 			recipeMenu.toggle(!recipeMenu.on, true);
5989 		}
5990 		else if (!core->isStateJumpPending())
5991 		{
5992 			toggleWorldMap();
5993 		}
5994 	}
5995 
5996 #ifdef AQUARIA_BUILD_SCENEEDITOR
5997 	if (id == ACTION_TOGGLESCENEEDITOR && !state)		toggleSceneEditor();
5998 #endif
5999 
6000 	if (dsq->isDeveloperKeys() || isSceneEditorActive())
6001 	{
6002 		if (id == ACTION_TOGGLEGRID && !state)			toggleGridRender();
6003 	}
6004 
6005 	if (isInGameMenu())
6006 	{
6007 		if (treasureMenu)
6008 		{
6009 			if (!state && !dsq->isNested())
6010 			{
6011 				if (dsq->menuSelectDelay == 0)
6012 				{
6013 					if (id == ACTION_PREVPAGE)
6014 					{
6015 						dsq->menuSelectDelay = MENUSELECTDELAY;
6016 						onPrevTreasurePage();
6017 						//menu[5]->setFocus(true);
6018 					}
6019 					if (id == ACTION_NEXTPAGE)
6020 					{
6021 						dsq->menuSelectDelay = MENUSELECTDELAY;
6022 						onNextTreasurePage();
6023 						//menu[5]->setFocus(true);
6024 					}
6025 				}
6026 			}
6027 		}
6028 		else if (foodMenu)
6029 		{
6030 			if (!state && !dsq->isNested())
6031 			{
6032 				if (dsq->menuSelectDelay == 0)
6033 				{
6034 					if (id == ACTION_PREVPAGE)
6035 					{
6036 						dsq->menuSelectDelay = MENUSELECTDELAY;
6037 						if (recipeMenu.on)
6038 							recipeMenu.goPrevPage();
6039 						else
6040 							onPrevFoodPage();
6041 					}
6042 					if (id == ACTION_NEXTPAGE)
6043 					{
6044 						dsq->menuSelectDelay = MENUSELECTDELAY;
6045 						if (recipeMenu.on)
6046 							recipeMenu.goNextPage();
6047 						else
6048 							onNextFoodPage();
6049 					}
6050 				}
6051 
6052 				if (id == ACTION_COOKFOOD)
6053 				{
6054 					if (!recipeMenu.on)
6055 						onCook();
6056 				}
6057 
6058 				if (id == ACTION_FOODLEFT)
6059 				{
6060 					if (recipeMenu.on)
6061 					{
6062 					}
6063 					else
6064 					{
6065 						for (int i = 0; i < foodHolders.size(); i++)
6066 						{
6067 							if (!foodHolders[i]->isTrash() && !foodHolders[i]->isEmpty())
6068 							{
6069 								foodHolders[i]->dropFood();
6070 								break;
6071 							}
6072 						}
6073 					}
6074 				}
6075 
6076 				if (id == ACTION_FOODRIGHT)
6077 				{
6078 					if (recipeMenu.on)
6079 					{
6080 					}
6081 					else
6082 					{
6083 						for (int i = 0; i < foodSlots.size(); i++)
6084 						{
6085 							if (foodSlots[i]->isCursorIn() && foodSlots[i]->getIngredient())
6086 							{
6087 								foodSlots[i]->moveRight();
6088 								break;
6089 							}
6090 						}
6091 					}
6092 				}
6093 
6094 				if (id == ACTION_FOODDROP)
6095 				{
6096 					if (recipeMenu.on)
6097 					{
6098 					}
6099 					else
6100 					{
6101 						int trashIndex = -1;
6102 						for (int i = 0; i < foodHolders.size(); i++)
6103 						{
6104 							if (foodHolders[i]->alpha.x > 0 && foodHolders[i]->alphaMod > 0 && foodHolders[i]->isTrash())
6105 							{
6106 								trashIndex = i;
6107 								break;
6108 							}
6109 						}
6110 						if (trashIndex >= 0)
6111 						{
6112 							int ingrIndex = -1;
6113 							for (int i = 0; i < foodSlots.size(); i++)
6114 							{
6115 								if (foodSlots[i]->isCursorIn() && foodSlots[i]->getIngredient())
6116 								{
6117 									ingrIndex = i;
6118 									break;
6119 								}
6120 							}
6121 							if (ingrIndex >= 0)
6122 							{
6123 								foodSlots[ingrIndex]->discard();
6124 							}
6125 						}
6126 					}
6127 				}
6128 			}
6129 		}
6130 	}
6131 }
6132 
toggleWorldMap()6133 void Game::toggleWorldMap()
6134 {
6135 	if (worldMapRender)
6136 	{
6137 		worldMapRender->toggle(!worldMapRender->isOn());
6138 	}
6139 }
6140 
applyState()6141 void Game::applyState()
6142 {
6143 	bool verbose = true;
6144 	applyingState = true;
6145 
6146 	helpText = 0;
6147 	helpUp = helpDown = 0;
6148 	inHelpScreen = false;
6149 	helpBG = 0;
6150 	helpBG2 = 0;
6151 
6152 	dsq->returnToScene = "";
6153 
6154 	// new place where mods get stopped!
6155 	// this lets recaching work
6156 	// (presumably because there has been time for the garbage to be cleared)
6157 	if (sceneToLoad == "title" && dsq->mod.isShuttingDown())
6158 	{
6159 		if (dsq->mod.isActive())
6160 		{
6161 			dsq->mod.stop();
6162 			dsq->continuity.reset();
6163 		}
6164 	}
6165 
6166 	dsq->collectScriptGarbage();
6167 
6168 	isCooking = false;
6169 	enqueuedPreviewRecipe = 0;
6170 
6171 	dsq->toggleBlackBars(false);
6172 
6173 	dsq->setTexturePointers();
6174 
6175 
6176 	moveFoodSlotToFront = 0;
6177 
6178 	cameraOffBounds = false;
6179 
6180 
6181 	ingOffY = 0;
6182 	ingOffYTimer = 0;
6183 
6184 	AquariaGuiElement::canDirMoveGlobal = true;
6185 
6186 	cookDelay = 0;
6187 
6188 	dsq->toggleVersionLabel(false);
6189 
6190 	activation = true;
6191 
6192 	active = true;
6193 
6194 	hasPlayedLow = false;
6195 
6196 	firstSchoolFish = true;
6197 	invincibleOnNested = true;
6198 
6199 
6200 	controlHintNotes.clear();
6201 
6202 	worldMapIndex = -1;
6203 
6204 	particleManager->setNumSuckPositions(10);
6205 
6206 	dropIngrNames.clear();
6207 
6208 	foodMenu = optionsMenu = petMenu = treasureMenu = false;
6209 
6210 	currentPet = 0;
6211 
6212 	bgSfxLoopPlaying2 = "";
6213 	lastBgSfxLoop = -1;
6214 	saveMusic = "";
6215 
6216 	timer = 0;
6217 	halfTimer = 0;
6218 
6219 	cameraFollowObject = 0;
6220 	cameraFollowEntity = 0;
6221 
6222 	shuttingDownGameState = false;
6223 	core->particlesPaused = false;
6224 	bNatural = false;
6225 	songLineRender = 0;
6226 	image = 0;
6227 
6228 	core->particleManager->collideFunction = game_collideParticle;
6229 	core->particleManager->specialFunction = game_wibbleParticle;
6230 
6231 	controlHint_ignoreClear = false;
6232 	inGameMenuExitState = 0;
6233 	int i = 0;
6234 	debugLog("Entering Game::applyState");
6235 	dsq->overlay->alpha = 1;
6236 	dsq->overlay->color = 0;
6237 
6238 
6239 	for (i = LR_ELEMENTS1; i <= LR_ELEMENTS12; i++) // LR_ELEMENTS13 is darkness, stop before that
6240 	{
6241 		dsq->game->setElementLayerVisible(i-LR_ELEMENTS1, true);
6242 	}
6243 
6244 	dsq->applyParallaxUserSettings();
6245 
6246 	controlHintTimer = 0;
6247 	cameraConstrained = true;
6248 	// reset parallax
6249 	RenderObjectLayer *l = 0;
6250 	for (i = LR_ELEMENTS10; i <= LR_ELEMENTS16; i++)
6251 	{
6252 		l = &dsq->renderObjectLayers[i];
6253 		l->followCamera = 0;
6254 		l->followCameraLock = 0;
6255 	}
6256 
6257 	dsq->resetLayerPasses();
6258 
6259 	ignoredActions.clear();
6260 
6261 	cameraLerpDelay = 0;
6262 	playingSongInMenu = -1;
6263 	sceneColor2 = Vector(1,1,1);
6264 	sceneColor3 = Vector(1,1,1);
6265 	if (core->afterEffectManager)
6266 	{
6267 		core->afterEffectManager->clear();
6268 		//core->afterEffectManager->addEffect(new RippleEffect());
6269 	}
6270 	Shot::shots.clear(); // the shots were deleted elsewhere, drop any remaining pointers
6271 	Shot::deleteShots.clear();
6272 	backdropQuad = 0;
6273 	clearObsRows();
6274 	inGameMenu = false;
6275 	sceneFlipped = false;
6276 	useWaterLevel = false;
6277 	waterLevel = saveWaterLevel = 0;
6278 	//miniMapHintPosition = Vector(8900, 14520);
6279 	currentInventoryPage = 0;
6280 
6281 	dsq->getRenderObjectLayer(LR_BLACKGROUND)->update = false;
6282 
6283 	//dsq->getRenderObjectLayer(LR_ELEMENTS5)->update = false;
6284 
6285 	backgroundImageRepeat = 1;
6286 	grad = 0;
6287 	maxZoom = -1;
6288 	maxLookDistance = 600;
6289 	saveFile = 0;
6290 	deathTimer = 0.9;
6291 	runGameOverScript = false;
6292 	paused = false;
6293 	//sceneColor = Vector(0.75, 0.75, 0.8);
6294 	sceneColor = Vector(1,1,1);
6295 	sceneName = "";
6296 	elementTemplatePack ="";
6297 	clearGrid();
6298 	clearPointers();
6299 	SkeletalSprite::clearCache();
6300 
6301 
6302 	StateObject::applyState();
6303 	//core->enable2D(800);
6304 
6305 	dsq->clearEntities();
6306 	dsq->clearElements();
6307 	elementWithMenu = 0;
6308 	//dsq->gui.menu.clearEntries();
6309 
6310 
6311 	progressBar = 0;
6312 
6313 	/*
6314 	progressBar = new AquariaProgressBar();
6315 	{
6316 		progressBar->position = Vector(400,300);
6317 	}
6318 	addRenderObject(progressBar, LR_PROGRESS);
6319 	*/
6320 
6321 	damageSprite = new Quad;
6322 	{
6323 		damageSprite->setTexture("damage");
6324 		damageSprite->alpha = 0;
6325 		damageSprite->autoWidth = AUTO_VIRTUALWIDTH;
6326 		damageSprite->autoHeight = AUTO_VIRTUALHEIGHT;
6327 		damageSprite->position = Vector(400,300);
6328 		damageSprite->followCamera = true;
6329 		damageSprite->scale.interpolateTo(Vector(1.1, 1.1), 0.75, -1, 1, 1);
6330 	}
6331 	addRenderObject(damageSprite, LR_DAMAGESPRITE);
6332 
6333 	bg2 = new Quad;
6334 	{
6335 		bg2->position = Vector(400, 300, -3/*-0.09f*/);
6336 		//bg2->color = Vector(0.9, 0.9, 0.9);
6337 		bg2->setTexture("missingImage");
6338 		bg2->setWidthHeight(900,600);
6339 		//bg2->blendEnabled = false;
6340 		bg2->followCamera =1;
6341 		bg2->alpha = 0.8;
6342 	}
6343 	addRenderObject(bg2, LR_BACKGROUND);
6344 
6345 	bg = new Quad;
6346 	{
6347 		bg->blendEnabled = false;
6348 		bg->position = Vector(400, 300, -2/*-0.09f*/);
6349 		//bg->color = Vector(0.9, 0.9, 0.9);
6350 		bg->setTexture("missingImage");
6351 		bg->setWidthHeight(900,600);
6352 		//bg->blendEnabled = true;
6353 		bg->followCamera =1;
6354 		bg->alpha = 1;
6355 	}
6356 	addRenderObject(bg, LR_BACKGROUND);
6357 
6358 
6359 	Vector mousePos(400,490);
6360 
6361 	controlHint_bg = new Quad;
6362 	{
6363 		controlHint_bg->followCamera = 1;
6364 		controlHint_bg->position = Vector(400,500);
6365 		controlHint_bg->color = 0;
6366 		controlHint_bg->alphaMod = 0.7;
6367 		//controlHint_bg->setTexture("HintBox");
6368 		controlHint_bg->setWidthHeight(core->getVirtualWidth(), 100);
6369 		controlHint_bg->autoWidth = AUTO_VIRTUALWIDTH;
6370 		controlHint_bg->alpha = 0;
6371 	}
6372 	addRenderObject(controlHint_bg, LR_HELP);
6373 
6374 	controlHint_text = new BitmapText(&dsq->smallFont);
6375 	{
6376 		controlHint_text->alpha = 0;
6377 		controlHint_text->setWidth(700);
6378 
6379 		controlHint_text->setAlign(ALIGN_LEFT);
6380 		controlHint_text->followCamera = 1;
6381 		controlHint_text->scale = Vector(0.9, 0.9);
6382 		//controlHint_text->setFontSize(14);
6383 	}
6384 	addRenderObject(controlHint_text, LR_HELP);
6385 
6386 	controlHint_image = new Quad;
6387 	{
6388 		controlHint_image->followCamera = 1;
6389 		controlHint_image->position = mousePos;
6390 		controlHint_image->alpha = 0;
6391 	}
6392 	addRenderObject(controlHint_image, LR_HELP);
6393 
6394 	controlHint_mouseLeft = new Quad;
6395 	{
6396 		controlHint_mouseLeft->followCamera = 1;
6397 		controlHint_mouseLeft->setTexture("Mouse-LeftButton");
6398 		controlHint_mouseLeft->position = mousePos;
6399 		controlHint_mouseLeft->alpha = 0;
6400 	}
6401 	addRenderObject(controlHint_mouseLeft, LR_HELP);
6402 
6403 
6404 	controlHint_mouseRight = new Quad;
6405 	{
6406 		controlHint_mouseRight->followCamera = 1;
6407 		controlHint_mouseRight->setTexture("Mouse-RightButton");
6408 		controlHint_mouseRight->position = mousePos;
6409 		controlHint_mouseRight->alpha = 0;
6410 	}
6411 	addRenderObject(controlHint_mouseRight, LR_HELP);
6412 
6413 	controlHint_mouseMiddle = new Quad;
6414 	{
6415 		controlHint_mouseMiddle->followCamera = 1;
6416 		controlHint_mouseMiddle->setTexture("Mouse-MiddleButton");
6417 		controlHint_mouseMiddle->position = mousePos;
6418 		controlHint_mouseMiddle->alpha = 0;
6419 	}
6420 	addRenderObject(controlHint_mouseMiddle, LR_HELP);
6421 
6422 	controlHint_mouseBody = new Quad;
6423 	{
6424 		controlHint_mouseBody->followCamera = 1;
6425 		controlHint_mouseBody->setTexture("Mouse-Body");
6426 		controlHint_mouseBody->position = mousePos;
6427 		controlHint_mouseBody->alpha = 0;
6428 	}
6429 	addRenderObject(controlHint_mouseBody, LR_HELP);
6430 
6431 
6432 	controlHint_shine = new Quad;
6433 	{
6434 		//controlHint_shine->setTexture("spiralglow");
6435 		controlHint_shine->color = Vector(1,1,1);
6436 		controlHint_shine->followCamera = 1;
6437 		controlHint_shine->position = Vector(400,500);
6438 		controlHint_shine->alphaMod = 0.3;
6439 		controlHint_shine->setWidthHeight(core->getVirtualWidth(), 100);
6440 		controlHint_shine->alpha = 0;
6441 		controlHint_shine->setBlendType(RenderObject::BLEND_ADD);
6442 	}
6443 	addRenderObject(controlHint_shine, LR_HELP);
6444 
6445 	li = 0;
6446 
6447 
6448 #ifdef AQUARIA_BUILD_SCENEEDITOR
6449 	if (dsq->canOpenEditor())
6450 	{
6451 		sceneEditor.init();
6452 	}
6453 #endif
6454 
6455 /*
6456 	if (liFlag == 100)
6457 	*/
6458 
6459 	if (verbose) debugLog("Creating Avatar");
6460 	avatar = new Avatar();
6461 	if (verbose) debugLog("Done new Avatar");
6462 
6463 	if (warpAreaType.empty())
6464 	{
6465 		if (positionToAvatar.x == 0 && positionToAvatar.y == 0)
6466 			avatar->position = Vector(dsq->avStart.x,dsq->avStart.y);
6467 		else
6468 			avatar->position = positionToAvatar;
6469 		positionToAvatar = Vector(0,0);
6470 	}
6471 	if (verbose) debugLog("Done warp");
6472 
6473 	if (verbose) debugLog("Create Li");
6474 	createLi();
6475 	if (verbose) debugLog("Done");
6476 
6477 
6478 
6479 
6480 	if (toFlip == 1)
6481 	{
6482 		dsq->game->avatar->flipHorizontal();
6483 		toFlip = -1;
6484 	}
6485 
6486 
6487 
6488 
6489 
6490 	// li
6491 	//if (true)
6492 
6493 
6494 	if (verbose) debugLog("WarpKeys");
6495 
6496 
6497 
6498 	if (verbose) debugLog("Done WarpKeys");
6499 
6500 	bindInput();
6501 
6502 	shapeDebug = 0;
6503 
6504 	/*
6505 	shapeDebug = new Quad;
6506 	shapeDebug->setWidthHeight(80, 80);
6507 	shapeDebug->color = Vector(1,1,0);
6508 	addRenderObject(shapeDebug, LR_ENTITIES);
6509 	*/
6510 
6511 
6512 
6513 	if (verbose) debugLog("Loading Scene");
6514 	if (!loadScene(sceneToLoad))
6515 	{
6516 		loadElementTemplates(elementTemplatePack);
6517 	}
6518 	if (verbose) debugLog("...Done");
6519 	backupSceneColor = sceneColor;
6520 
6521 	dsq->continuity.worldMap.revealMap(sceneName);
6522 
6523 	colorTest();
6524 
6525 	if (!warpAreaType.empty())
6526 	{
6527 		for (int i = 0; i < warpAreas.size(); i++)
6528 		{
6529 			WarpArea *a = &warpAreas[i];
6530 			if (a->warpAreaType == warpAreaType)
6531 			{
6532 				int extra=96;
6533 				if (a->radius)
6534 					avatar->position = a->position + (spawnOffset*(a->radius+extra));
6535 				else
6536 				{
6537 					Vector s(spawnOffset.x*(a->w+extra), spawnOffset.y*(a->h+extra));
6538 					avatar->position = a->position + s;
6539 				}
6540 				break;
6541 			}
6542 		}
6543 		warpAreaType = "";
6544 	}
6545 
6546 
6547 	if (verbose) debugLog("Adding Avatar");
6548 	addRenderObject(avatar, LR_ENTITIES);
6549 	//cameraFollow = &avatar->position;
6550 	setCameraFollowEntity(avatar);
6551 	if (verbose) debugLog("...Done");
6552 
6553 
6554 	currentRender = new CurrentRender();
6555 	addRenderObject(currentRender, LR_ELEMENTS3);
6556 
6557 	steamRender = new SteamRender();
6558 	addRenderObject(steamRender, LR_ELEMENTS9);
6559 
6560 	songLineRender = new SongLineRender();
6561 	addRenderObject(songLineRender, LR_HUD);
6562 
6563 	gridRender = new GridRender(OT_INVISIBLE);
6564 	gridRender->color = Vector(1, 0, 0);
6565 	addRenderObject(gridRender, LR_DEBUG_TEXT);
6566 	gridRender->alpha = 0;
6567 
6568 	gridRender2 = new GridRender(OT_HURT);
6569 	gridRender2->color = Vector(1, 1, 0);
6570 	addRenderObject(gridRender2, LR_DEBUG_TEXT);
6571 	gridRender2->alpha = 0;
6572 
6573 	gridRender3 = new GridRender(OT_INVISIBLEIN);
6574 	gridRender3->color = Vector(1, 0.5f, 0);
6575 	addRenderObject(gridRender3, LR_DEBUG_TEXT);
6576 	gridRender3->alpha = 0;
6577 
6578 	edgeRender = new GridRender(OT_BLACKINVIS);
6579 	edgeRender->color = Vector(0.3f, 0, 0.6f);
6580 	addRenderObject(edgeRender, LR_DEBUG_TEXT);
6581 	edgeRender->alpha = 0;
6582 
6583 	gridRenderEnt = new GridRender(OT_INVISIBLEENT);
6584 	gridRenderEnt->color = Vector(0, 1, 0.5);
6585 	addRenderObject(gridRenderEnt, LR_DEBUG_TEXT);
6586 	gridRenderEnt->alpha = 0;
6587 
6588 	gridRenderUser1 = new GridRender(OT_USER1);
6589 	addRenderObject(gridRenderUser1, LR_DEBUG_TEXT);
6590 	gridRenderUser1->color = Vector(1, 0, 1);
6591 	gridRenderUser1->alpha = 0;
6592 
6593 	gridRenderUser2 = new GridRender(OT_USER2);
6594 	addRenderObject(gridRenderUser2, LR_DEBUG_TEXT);
6595 	gridRenderUser2->color = Vector(1, 1, 1);
6596 	gridRenderUser2->alpha = 0;
6597 
6598 	waterSurfaceRender = new WaterSurfaceRender();
6599 	//waterSurfaceRender->setRenderPass(-1);
6600 	addRenderObject(waterSurfaceRender, LR_WATERSURFACE);
6601 
6602 	GridRender *blackRender = new GridRender(OT_BLACK);
6603 	blackRender->color = Vector(0, 0, 0);
6604 	//blackRender->alpha = 0;
6605 	blackRender->blendEnabled = false;
6606 	addRenderObject(blackRender, LR_ELEMENTS4);
6607 
6608 
6609 	hudUnderlay = new Quad;
6610 	hudUnderlay->color = 0;
6611 	hudUnderlay->position = Vector(400,300);
6612 	//hudUnderlay->scale = Vector(800, 600);
6613 	hudUnderlay->autoWidth = AUTO_VIRTUALWIDTH;
6614 	hudUnderlay->autoHeight = AUTO_VIRTUALHEIGHT;
6615 	hudUnderlay->alpha = 0;
6616 	hudUnderlay->followCamera = 1;
6617 	addRenderObject(hudUnderlay, LR_HUDUNDERLAY);
6618 
6619 	autoMap = 0;
6620 	/*
6621 	autoMap = new AutoMap;
6622 	addRenderObject(autoMap, LR_MESSAGEBOX);
6623 	*/
6624 
6625 	miniMapRender = 0;
6626 
6627 	//miniMapRender->position = Vector(400,300);
6628 
6629 	miniMapRender = new MiniMapRender;
6630 
6631 	//miniMapRender->position = Vector(740,540);
6632 	// position = (vw,vh) - (scale*100)
6633 	// set in minimaprender::onupdate
6634 	miniMapRender->scale = Vector(0.55, 0.55);
6635 
6636 
6637 	/*
6638 	miniMapRender->position = Vector(750,550);
6639 	miniMapRender->scale = Vector(0.5, 0.5);
6640 	*/
6641 
6642 	//miniMapRender->scale = Vector(8,8);
6643 	addRenderObject(miniMapRender, LR_MINIMAP);
6644 
6645 	timerText = new BitmapText(&dsq->smallFont);
6646 	timerText->position = Vector(745, 550);
6647 	timerText->alpha = 0;
6648 	timerText->followCamera = 1;
6649 	addRenderObject(timerText, LR_MINIMAP);
6650 
6651 	worldMapRender = 0;
6652 
6653 	if(dsq->mod.isActive() && dsq->mod.mapRevealMethod != REVEAL_UNSPECIFIED)
6654 		WorldMapRender::setRevealMethod(dsq->mod.mapRevealMethod);
6655 	else
6656 		WorldMapRender::setRevealMethod((WorldMapRevealMethod)dsq->user.video.worldMapRevealMethod);
6657 
6658 	worldMapRender = new WorldMapRender;
6659 	addRenderObject(worldMapRender, LR_WORLDMAP);
6660 	// to hide minimap
6661 	//miniMapRender->position += Vector(800,0);
6662 
6663 	sceneToLoad="";
6664 
6665 	if (!fromScene.empty())
6666 	{
6667 		stringToLower(fromScene);
6668 		debugLog("fromScene: " + fromScene + " fromWarpType: " + fromWarpType);
6669 		float smallestDist = HUGE_VALF;
6670 		Path *closest = 0;
6671 		Vector closestPushOut;
6672 		bool doFlip = false;
6673 		for (int i = 0; i < dsq->game->getNumPaths(); i++)
6674 		{
6675 			Path *p = dsq->game->getPath(i);
6676 			Vector pos = p->nodes[0].position;
6677 			if (p && (nocasecmp(p->warpMap, fromScene)==0))
6678 			{
6679 				float dist = -1;
6680 				bool go = false;
6681 				Vector pushOut;
6682 				switch(fromWarpType)
6683 				{
6684 				case CHAR_RIGHT:
6685 					go = (p->warpType == CHAR_LEFT);
6686 					pushOut = Vector(1,0);
6687 					dist = fabsf(fromPosition.y - pos.y);
6688 					doFlip = true;
6689 				break;
6690 				case CHAR_LEFT:
6691 					go = (p->warpType == CHAR_RIGHT);
6692 					pushOut = Vector(-1,0);
6693 					dist = fabsf(fromPosition.y - pos.y);
6694 				break;
6695 				case CHAR_UP:
6696 					go = (p->warpType == CHAR_DOWN);
6697 					pushOut = Vector(0, -1);
6698 					dist = fabsf(fromPosition.x - pos.x);
6699 				break;
6700 				case CHAR_DOWN:
6701 					go = (p->warpType == CHAR_UP);
6702 					pushOut = Vector(0, 1);
6703 					dist = fabsf(fromPosition.x - pos.x);
6704 				break;
6705 				}
6706 				if (go)
6707 				{
6708 					if (dist == -1)
6709 					{
6710 						debugLog(p->warpMap + ": warpType is wonky");
6711 					}
6712 					else if (dist < smallestDist)
6713 					{
6714 						smallestDist = dist;
6715 						closest = p;
6716 						closestPushOut = pushOut;
6717 					}
6718 				}
6719 			}
6720 		}
6721 		if (closest)
6722 		{
6723 			debugLog("warping avatar to node: "  + closest->name);
6724 			// this value of 8 is just nothing really
6725 			// it short work with default value 1
6726 			// just gives the player some room to move without heading straight back
6727 			// into the warp
6728 			// LOL to the above!!! :DDDDD
6729 			avatar->position = closest->getEnterPosition(50);
6730 			if (doFlip)
6731 				avatar->flipHorizontal();
6732 			/*
6733 			avatar->position = closest->nodes[0].position;
6734 			avatar->position += closestPushOut * 80;
6735 			*/
6736 
6737 			/*
6738 			fromVel = Vector(0,1);
6739 			avatar->rotateToVec(fromVel, 0.001);
6740 			*/
6741 		}
6742 		else
6743 		{
6744 			debugLog("ERROR: Could not find a node to warp the player to!");
6745 		}
6746 		fromScene = "";
6747 	}
6748 	else if (!toNode.empty())
6749 	{
6750 		Path *p = dsq->game->getPathByName(toNode);
6751 		if (p)
6752 		{
6753 			avatar->position = p->nodes[0].position;
6754 		}
6755 		toNode = "";
6756 	}
6757 	/*
6758 	if (!fromVel.isZero())
6759 	{
6760 		//avatar->vel = fromVel;
6761 		avatar->rotateToVec(fromVel, 0.001);
6762 	}
6763 	*/
6764 
6765 	avatar->setWasUnderWater();
6766 	if (!avatar->isUnderWater())
6767 	{
6768 		avatar->setMaxSpeed(dsq->v.maxOutOfWaterSpeed);
6769 		avatar->currentMaxSpeed = dsq->v.maxOutOfWaterSpeed;
6770 	}
6771 
6772 	if (avatar->position.isZero() || avatar->position == Vector(1,1))
6773 	{
6774 		Path *p = 0;
6775 		if ((p = getPathByName("NAIJASTART")) != 0 || (p = getPathByName("NAIJASTART L")) != 0)
6776 		{
6777 			avatar->position = p->nodes[0].position;
6778 		}
6779 		else if ((p = getPathByName("NAIJASTART R")) != 0)
6780 		{
6781 			avatar->position = p->nodes[0].position;
6782 			avatar->flipHorizontal();
6783 		}
6784 	}
6785 
6786 
6787 	//positionLi
6788 	if (li)
6789 	{
6790 		li->position = avatar->position + Vector(8,8);
6791 	}
6792 
6793 	toNode = "";
6794 
6795 	createInGameMenu();
6796 	hideInGameMenu(false);
6797 
6798 	core->cacheRender();
6799 
6800 	cameraInterp.stop();
6801 
6802 	core->globalScale = dsq->continuity.zoom;
6803 	//core->globalScaleChanged();
6804 	avatar->myZoom = dsq->continuity.zoom;
6805 
6806 	cameraInterp = avatar->position;
6807 	core->cameraPos = getCameraPositionFor(avatar->position);
6808 
6809 	core->sort();
6810 
6811 	if (dsq->mod.isActive())
6812 		dsq->runScript(dsq->mod.getPath() + "scripts/premap_" + sceneName + ".lua", "init", true);
6813 	else
6814 		dsq->runScript("scripts/maps/premap_"+sceneName+".lua", "init", true);
6815 
6816 	std::string musicToPlay = this->musicToPlay;
6817 	if (!overrideMusic.empty())
6818 	{
6819 		musicToPlay = overrideMusic;
6820 	}
6821 
6822 	if(cookingScript)
6823 	{
6824 		dsq->scriptInterface.closeScript(cookingScript);
6825 		cookingScript = NULL;
6826 	}
6827 
6828 	if (dsq->mod.isActive())
6829 		cookingScript = dsq->scriptInterface.openScript(dsq->mod.getPath() + "scripts/cooking.lua", true);
6830 	else
6831 		cookingScript = dsq->scriptInterface.openScript("scripts/global/cooking.lua", true);
6832 
6833 	//INFO: this used to be here to start fading out the music
6834 	// before the level had begun
6835 	/*
6836 	if (dsq->sound->isPlayingMusic())
6837 	{
6838 		if (dsq->sound->currentMusic.find(musicToPlay) != std::string::npos)
6839 		{
6840 		}
6841 		else
6842 		{
6843 			dsq->sound->fadeMusic(SFT_CROSS, 1);
6844 		}
6845 	}
6846 	*/
6847 
6848 	/*
6849 	// HACK: to get the player on the map if there's an error with the warp coords
6850 	while(dsq->game->collideCircleWithGrid(avatar->position, 32))
6851 	{
6852 		if (avatar->position.y < 200)
6853 			avatar->position.y += 200;
6854 		avatar->position += Vector(40,0);
6855 		avatar->clampPosition();
6856 	}
6857 	*/
6858 
6859 	updateMiniMapHintPosition();
6860 
6861 	createPets();
6862 
6863 
6864 	postInitEntities();
6865 
6866 
6867 	/*
6868 	core->sound->musicVolume(1.0, 0.5);
6869 	core->sound->sfxVolume(1.0, 0.5);
6870 	*/
6871 
6872 	bool musicchanged = updateMusic();
6873 
6874 
6875 
6876 	dsq->loops.bg = BBGE_AUDIO_NOCHANNEL;
6877 
6878 	if (!bgSfxLoop.empty())
6879 	{
6880 		core->sound->loadLocalSound(bgSfxLoop);
6881 	}
6882 
6883 	if (!airSfxLoop.empty())
6884 	{
6885 		core->sound->loadLocalSound(airSfxLoop);
6886 	}
6887 
6888 	if (dsq->continuity.getWorldType() != WT_NORMAL)
6889 		dsq->continuity.applyWorldEffects(dsq->continuity.getWorldType(), 0, musicchanged);
6890 
6891 
6892 	if (verbose) debugLog("initAvatar");
6893 
6894 	dsq->continuity.initAvatar(avatar);
6895 
6896 	if (verbose) debugLog("Done initAvatar");
6897 
6898 
6899 	if (verbose) debugLog("reset timer");
6900 	core->resetTimer();
6901 
6902 	if (verbose) debugLog("paths init");
6903 	int pathSz = getNumPaths();
6904 	for (i = 0; i < pathSz; i++)
6905 	{
6906 		getPath(i)->init();
6907 	}
6908 
6909 	debugLog("Updating bgSfxLoop");
6910 	updateBgSfxLoop();
6911 
6912 	// Must be _before_ the init script, since some init scripts run
6913 	// cutscenes immediately.  --achurch
6914 	dsq->subtitlePlayer.show(0.25);
6915 
6916 	if (verbose) debugLog("loading map init script");
6917 	if (dsq->mod.isActive())
6918 		dsq->runScript(dsq->mod.getPath() + "scripts/map_" + sceneName + ".lua", "init", true);
6919 	else
6920 		dsq->runScript("scripts/maps/map_"+sceneName+".lua", "init", true);
6921 
6922 	if (!dsq->doScreenTrans && (dsq->overlay->alpha != 0 && !dsq->overlay->alpha.isInterpolating()))
6923 	{
6924 		if (verbose) debugLog("fading in");
6925 		debugLog("FADEIN");
6926 		//dsq->overlay->alpha = 1;
6927 		dsq->overlay->alpha.interpolateTo(0, 1);
6928 
6929 		core->resetTimer();
6930 		avatar->disableInput();
6931 		core->main(0.5);
6932 		avatar->enableInput();
6933 		core->resetTimer();
6934 	}
6935 
6936 	if (dsq->doScreenTrans)
6937 	{
6938 		debugLog("SCREENTRANS!");
6939 		core->resetTimer();
6940 		dsq->toggleCursor(false, 0);
6941 		dsq->doScreenTrans = false;
6942 
6943 		dsq->transitionSaveSlots();
6944 		dsq->overlay->alpha = 0;
6945 		dsq->main(0.5);
6946 		dsq->toggleCursor(true);
6947 		dsq->tfader->alpha.interpolateTo(0, 0.2);
6948 		dsq->main(0.21);
6949 		dsq->clearSaveSlots(false);
6950 	}
6951 
6952 	if (verbose) debugLog("reset timer");
6953 
6954 	applyingState = false;
6955 
6956 	if (!dsq->doScreenTrans)
6957 	{
6958 		dsq->toggleCursor(true, 0.5);
6959 	}
6960 
6961 	dsq->forceInputGrabOff();
6962 
6963 	debugLog("Game::applyState Done");
6964 }
6965 
bindInput()6966 void Game::bindInput()
6967 {
6968 	if (!(this->applyingState || this->isActive())) return;
6969 
6970 	ActionMapper::clearActions();
6971 	//ActionMapper::clearCreatedEvents();
6972 
6973 
6974 #ifdef AQUARIA_BUILD_SCENEEDITOR
6975 	if (dsq->canOpenEditor())
6976 	{
6977 		addAction(ACTION_TOGGLESCENEEDITOR, KEY_TAB);
6978 	}
6979 #endif
6980 
6981 
6982 	dsq->user.control.actionSet.importAction(this, "PrimaryAction", ACTION_PRIMARY);
6983 	dsq->user.control.actionSet.importAction(this, "SecondaryAction", ACTION_SECONDARY);
6984 
6985 	dsq->user.control.actionSet.importAction(this, "Escape",		ACTION_ESC);
6986 
6987 	dsq->user.control.actionSet.importAction(this, "WorldMap",		ACTION_TOGGLEWORLDMAP);
6988 
6989 	dsq->user.control.actionSet.importAction(this, "ToggleHelp",	ACTION_TOGGLEHELPSCREEN);
6990 
6991 	// used for scrolling help text
6992 	dsq->user.control.actionSet.importAction(this, "SwimUp",		ACTION_SWIMUP);
6993 	dsq->user.control.actionSet.importAction(this, "SwimDown",		ACTION_SWIMDOWN);
6994 	dsq->user.control.actionSet.importAction(this, "SwimLeft",		ACTION_SWIMLEFT);
6995 	dsq->user.control.actionSet.importAction(this, "SwimRight",		ACTION_SWIMRIGHT);
6996 
6997 
6998 	dsq->user.control.actionSet.importAction(this, "PrevPage",		ACTION_PREVPAGE);
6999 	dsq->user.control.actionSet.importAction(this, "NextPage",		ACTION_NEXTPAGE);
7000 	dsq->user.control.actionSet.importAction(this, "CookFood",		ACTION_COOKFOOD);
7001 	dsq->user.control.actionSet.importAction(this, "FoodLeft",		ACTION_FOODLEFT);
7002 	dsq->user.control.actionSet.importAction(this, "FoodRight",		ACTION_FOODRIGHT);
7003 	dsq->user.control.actionSet.importAction(this, "FoodDrop",		ACTION_FOODDROP);
7004 
7005 	if (dsq->canOpenEditor())
7006 	{
7007 		//addAction(MakeFunctionEvent(Game, toggleMiniMapRender), KEY_M, 0);
7008 		addAction(ACTION_TOGGLEGRID, KEY_F9);
7009 	}
7010 
7011 	/*
7012 	addAction(ACTION_MENULEFT,	KEY_LEFT);
7013 	addAction(ACTION_MENURIGHT,	KEY_RIGHT);
7014 	addAction(ACTION_MENUUP,	KEY_UP);
7015 	addAction(ACTION_MENUDOWN,	KEY_DOWN);
7016 
7017 	dsq->user.control.actionSet.importAction(this, "SwimLeft",		ACTION_MENULEFT);
7018 	dsq->user.control.actionSet.importAction(this, "SwimRight",		ACTION_MENURIGHT);
7019 	dsq->user.control.actionSet.importAction(this, "SwimUp",		ACTION_MENUUP);
7020 	dsq->user.control.actionSet.importAction(this, "SwimDown",		ACTION_MENUDOWN);
7021 
7022 	addAction(ACTION_MENULEFT,	JOY1_DPAD_LEFT);
7023 	addAction(ACTION_MENURIGHT,	JOY1_DPAD_RIGHT);
7024 	addAction(ACTION_MENUUP,	JOY1_DPAD_UP);
7025 	addAction(ACTION_MENUDOWN,	JOY1_DPAD_DOWN);
7026 	*/
7027 
7028 	addAction(ACTION_MENULEFT,	JOY1_STICK_LEFT);
7029 	addAction(ACTION_MENURIGHT,	JOY1_STICK_RIGHT);
7030 	addAction(ACTION_MENUUP,	JOY1_STICK_UP);
7031 	addAction(ACTION_MENUDOWN,	JOY1_STICK_DOWN);
7032 
7033 	// To capture quick song keys via script
7034 	dsq->user.control.actionSet.importAction(this, "SongSlot1",		ACTION_SONGSLOT1);
7035 	dsq->user.control.actionSet.importAction(this, "SongSlot2",		ACTION_SONGSLOT2);
7036 	dsq->user.control.actionSet.importAction(this, "SongSlot3",		ACTION_SONGSLOT3);
7037 	dsq->user.control.actionSet.importAction(this, "SongSlot4",		ACTION_SONGSLOT4);
7038 	dsq->user.control.actionSet.importAction(this, "SongSlot5",		ACTION_SONGSLOT5);
7039 	dsq->user.control.actionSet.importAction(this, "SongSlot6",		ACTION_SONGSLOT6);
7040 	dsq->user.control.actionSet.importAction(this, "SongSlot7",		ACTION_SONGSLOT7);
7041 	dsq->user.control.actionSet.importAction(this, "SongSlot8",		ACTION_SONGSLOT8);
7042 	dsq->user.control.actionSet.importAction(this, "SongSlot9",		ACTION_SONGSLOT9);
7043 	dsq->user.control.actionSet.importAction(this, "SongSlot10",	ACTION_SONGSLOT10);
7044 
7045 	dsq->user.control.actionSet.importAction(this, "Revert",		ACTION_REVERT);
7046 
7047 	dsq->user.control.actionSet.importAction(this, "Look",			ACTION_LOOK);
7048 	dsq->user.control.actionSet.importAction(this, "Roll",			ACTION_ROLL);
7049 
7050 	if (avatar)
7051 		avatar->bindInput();
7052 
7053 	if (worldMapRender)
7054 		worldMapRender->bindInput();
7055 }
7056 
ingType(const std::vector<IngredientData * > & list,IngredientType type,int amount=1)7057 bool ingType(const std::vector<IngredientData*> &list, IngredientType type, int amount=1)
7058 {
7059 	int c = 0;
7060 	for (int i = 0; i < list.size(); i++)
7061 	{
7062 		IngredientData *data = list[i];
7063 		if ((data->marked < data->held) && (data->type == type || type == IT_ANYTHING))
7064 		{
7065 			if (type != IT_ANYTHING)
7066 				data->marked++;
7067 			c++;
7068 			if (c == amount)
7069 				return true;
7070 		}
7071 	}
7072 	return false;
7073 }
7074 
ingName(const std::vector<IngredientData * > & list,const std::string & name,int amount=1)7075 bool ingName(const std::vector<IngredientData*> &list, const std::string &name, int amount=1)
7076 {
7077 	int c = 0;
7078 	for (int i = 0; i < list.size(); i++)
7079 	{
7080 		IngredientData *data = list[i];
7081 		if ((data->marked < data->held) && (nocasecmp(data->name, name)==0))//data->name == name)
7082 		{
7083 			data->marked++;
7084 			c++;
7085 			if (c == amount)
7086 				return true;
7087 		}
7088 	}
7089 	return false;
7090 }
7091 
7092 const int numTreasures = 16*2;
7093 
onPrevTreasurePage()7094 void Game::onPrevTreasurePage()
7095 {
7096 	if (currentTreasurePage > 0)
7097 	{
7098 		dsq->sound->playSfx("menu-switch", 0.5);
7099 		dsq->spawnParticleEffect("menu-switch", worldLeftCenter, 0, 0, LR_HUD3, 1);
7100 
7101 		currentTreasurePage--;
7102 		refreshTreasureSlots();
7103 	}
7104 	else
7105 	{
7106 		if (numTreasures > 0)
7107 		{
7108 			dsq->sound->playSfx("menu-switch", 0.5);
7109 			dsq->spawnParticleEffect("menu-switch", worldLeftCenter, 0, 0, LR_HUD3, 1);
7110 
7111 			currentTreasurePage = ((numTreasures-1)/treasurePageSize);
7112 			refreshTreasureSlots();
7113 		}
7114 	}
7115 }
7116 
onNextTreasurePage()7117 void Game::onNextTreasurePage()
7118 {
7119 	if ((currentTreasurePage+1)*treasurePageSize < numTreasures)
7120 	{
7121 		dsq->sound->playSfx("menu-switch", 0.5);
7122 		dsq->spawnParticleEffect("menu-switch", worldLeftCenter, 0, 0, LR_HUD3, 1);
7123 
7124 		currentTreasurePage++;
7125 		refreshTreasureSlots();
7126 	}
7127 	else
7128 	{
7129 		if (currentTreasurePage != 0)
7130 		{
7131 			dsq->sound->playSfx("menu-switch", 0.5);
7132 			dsq->spawnParticleEffect("menu-switch", worldLeftCenter, 0, 0, LR_HUD3, 1);
7133 
7134 			currentTreasurePage = 0;
7135 			refreshTreasureSlots();
7136 		}
7137 	}
7138 }
7139 
onPrevFoodPage()7140 void Game::onPrevFoodPage()
7141 {
7142 	int lastFoodPage = currentFoodPage;
7143 	if (currentFoodPage > 0)
7144 	{
7145 		currentFoodPage--;
7146 		refreshFoodSlots(false);
7147 	}
7148 	else
7149 	{
7150 		if (dsq->continuity.hasIngredients())
7151 		{
7152 			currentFoodPage = ((dsq->continuity.ingredientCount()-1)/foodPageSize);
7153 			refreshFoodSlots(false);
7154 		}
7155 	}
7156 
7157 	std::ostringstream os;
7158 	os << "food page: " << currentFoodPage;
7159 	debugLog(os.str());
7160 
7161 	if (currentFoodPage != lastFoodPage)
7162 	{
7163 		dsq->sound->playSfx("menu-switch", 0.5);
7164 		dsq->spawnParticleEffect("menu-switch", worldLeftCenter, 0, 0, LR_HUD3, 1);
7165 	}
7166 }
7167 
onNextFoodPage()7168 void Game::onNextFoodPage()
7169 {
7170 	int lastFoodPage = currentFoodPage;
7171 	if ((currentFoodPage+1)*foodPageSize < dsq->continuity.ingredientCount())
7172 	{
7173 		currentFoodPage++;
7174 		refreshFoodSlots(false);
7175 	}
7176 	else
7177 	{
7178 		if (currentFoodPage != 0)
7179 		{
7180 			currentFoodPage = 0;
7181 			refreshFoodSlots(false);
7182 		}
7183 	}
7184 
7185 	if (currentFoodPage != lastFoodPage)
7186 	{
7187 		dsq->sound->playSfx("menu-switch", 0.5);
7188 		dsq->spawnParticleEffect("menu-switch", worldLeftCenter, 0, 0, LR_HUD3, 1);
7189 	}
7190 }
7191 
onUseTreasure()7192 void Game::onUseTreasure()
7193 {
7194 	debugLog("Use Treasure!");
7195 
7196 	if (selectedTreasureFlag != -1)
7197 	{
7198 		onUseTreasure(selectedTreasureFlag);
7199 	}
7200 }
7201 
onUseTreasure(int flag)7202 void Game::onUseTreasure(int flag)
7203 {
7204 	if(dsq->mod.isActive())
7205 		dsq->runScriptNum(dsq->mod.getPath() + "scripts/menu-treasures.lua", "useTreasure", flag);
7206 	else
7207 		dsq->runScriptNum("scripts/global/menu-treasures.lua", "useTreasure", flag);
7208 }
7209 
findRecipe(const std::vector<IngredientData * > & list)7210 Recipe *Game::findRecipe(const std::vector<IngredientData*> &list)
7211 {
7212 	if (list.size() < 2) return 0;
7213 
7214 	// there will be a number of types and a number of names
7215 	// the types and names DO NOT overlap
7216 	int rc = 0;
7217 	Recipe *r = 0;
7218 	Recipe *tr = 0;
7219 	int q = 0, q2 = 0;
7220 	for ( rc = 0; rc < dsq->continuity.recipes.size(); rc++)
7221 	{
7222 		for (int i = 0; i < list.size(); i++) list[i]->marked = 0;
7223 
7224 		tr = 0;
7225 		r = &dsq->continuity.recipes[rc];
7226 		tr = r;
7227 		q = 0;
7228 
7229 		// get the amount of ingredients provided by the player
7230 		int listAmount = list.size();
7231 
7232 		// get the amount of ingredients required
7233 		int recipeAmount = 0;
7234 
7235 		for (int i = 0; i < r->types.size(); i++)
7236 			recipeAmount += r->types[i].amount;
7237 
7238 		for (int i = 0; i < r->names.size(); i++)
7239 			recipeAmount += r->names[i].amount;
7240 
7241 		if (listAmount != recipeAmount)
7242 			continue;
7243 
7244 		for (int c = 0; c < r->types.size(); c++)
7245 		{
7246 			RecipeType *t = &r->types[c];
7247 			if (ingType(list, t->type, t->amount))
7248 				q++;
7249 			else
7250 				break;
7251 		}
7252 
7253 		/*
7254 		// if all the types are checked
7255 		// AND there are no names to check
7256 		// then you found it!
7257 		if (q == r->types.size() && q > 0 && r->names.empty())
7258 		{
7259 			return tr;
7260 		}
7261 		*/
7262 
7263 		// this check is _kinda_ unnecessary... but we'll see
7264 		if (q == r->types.size())
7265 		{
7266 			q2 = 0;
7267 			for (int c = 0; c < r->names.size(); c++)
7268 			{
7269 				RecipeName *n = &r->names[c];
7270 				if (ingName(list, n->name, n->amount))
7271 					q2++;
7272 				else
7273 					break;
7274 			}
7275 			if (q2 == r->names.size())
7276 			{
7277 				return r;
7278 			}
7279 			/*
7280 			// if there were actually types to check
7281 			// and they were checked successfully
7282 			// (being in this section of code implies that there were no types OR there was a successful full check)
7283 			else if (q>0 && tr)
7284 			{
7285 				// return the ingredient we found in types
7286 
7287 				// but this is kind of silly.
7288 				// would make more sense to return earlier
7289 				return tr;
7290 			}
7291 			*/
7292 		}
7293 	}
7294 
7295 	for (int i = 0; i < list.size(); i++) list[i]->marked = 0;
7296 
7297 	if (rc == dsq->continuity.recipes.size())
7298 	{
7299 		/*
7300 		data = dsq->continuity.getIngredientByName("SeaLoaf");
7301 		if (data)
7302 		{
7303 			dsq->continuity.pickupIngredient(data);
7304 		}
7305 		*/
7306 	}
7307 
7308 	return 0;
7309 }
7310 
updateCookList()7311 void Game::updateCookList()
7312 {
7313 	cookList.clear();
7314 	for (int i = 0; i < foodHolders.size(); i++)
7315 	{
7316 		IngredientData *ing = foodHolders[i]->getIngredient();
7317 		if (!foodHolders[i]->isTrash() && ing)
7318 		{
7319 			std::ostringstream os;
7320 			os << "cooklist: " << ing->name;
7321 			debugLog(os.str());
7322 			cookList.push_back(ing);
7323 		}
7324 	}
7325 }
7326 
onRecipes()7327 void Game::onRecipes()
7328 {
7329 	if (foodMenu)
7330 	{
7331 		toggleRecipeList(!recipeMenu.on);
7332 	}
7333 }
7334 
onKeyConfig()7335 void Game::onKeyConfig()
7336 {
7337 	dsq->screenTransition->capture();
7338 	toggleKeyConfigMenu(true);
7339 	dsq->screenTransition->transition(MENUPAGETRANSTIME);
7340 }
7341 
7342 #define DEBUG_COOK
7343 
onCook()7344 void Game::onCook()
7345 {
7346 	if (recipeMenu.on) return;
7347 	if (cookDelay > 0) return;
7348 
7349 	debugLog("Cook!");
7350 
7351 	//std::vector<IngredientData*> list;
7352 	updateCookList();
7353 
7354 	if (cookList.size() < 2 || recipeMenu.on) return;
7355 
7356 	AquariaGuiElement::canDirMoveGlobal = false;
7357 
7358 	cookDelay = 0.4;
7359 
7360 	bool cooked = false;
7361 
7362 	isCooking = true;
7363 
7364 	IngredientData *data=0;
7365 	Recipe *r = findRecipe(cookList);
7366 
7367 	if (r)
7368 		data = dsq->continuity.getIngredientDataByName(r->result);
7369 	else if(cookingScript)
7370 	{
7371 		const char *p1 = cookList[0]->name.c_str();
7372 		const char *p2 = cookList[1]->name.c_str();
7373 		const char *p3 = cookList.size() >= 3 ? cookList[2]->name.c_str() : "";
7374 		std::string ingname;
7375 		if(cookingScript->call("cookFailure", p1, p2, p3, &ingname))
7376 		{
7377 			if(ingname.length())
7378 				data = dsq->continuity.getIngredientDataByName(ingname);
7379 			if(!data)
7380 				goto endcook;
7381 		}
7382 	}
7383 
7384 	if(!data)
7385 	{
7386 		dsq->sound->playSfx("Denied");
7387 		data = dsq->continuity.getIngredientDataByName("SeaLoaf");
7388 
7389 		bool tooMany = data && dsq->continuity.isIngredientFull(data);
7390 
7391 		if (!tooMany)
7392 		{
7393 			int f = dsq->continuity.getFlag(FLAG_SEALOAFANNOYANCE);
7394 			f++;
7395 			if (f >= 3)
7396 			{
7397 				dsq->voiceInterupt("naija_sealoaf");
7398 				f = 0;
7399 			}
7400 			dsq->continuity.setFlag(FLAG_SEALOAFANNOYANCE, f);
7401 		}
7402 	}
7403 
7404 	if (data)
7405 	{
7406 		cooked = !dsq->continuity.isIngredientFull(data);
7407 	}
7408 
7409 	if (cooked)
7410 	{
7411 		debugLog("Cooked something!");
7412 
7413 		// do animationy stuff.
7414 
7415 		core->mouse.buttonsEnabled = false;
7416 
7417 		bool longAnim = true;
7418 		int cooks = dsq->continuity.getFlag(FLAG_COOKS);
7419 
7420 		if (cooks >= 4)
7421 			longAnim = false;
7422 
7423 		for (int i = foodHolders.size()-1; i >= 0; i--)
7424 			if (foodHolders[i]->alpha.x > 0 && !foodHolders[i]->isEmpty() && !foodHolders[i]->isTrash())
7425 				foodHolders[i]->animateLid(true, longAnim);
7426 
7427 		//dsq->main(0.2);
7428 
7429 
7430 		if (longAnim)
7431 		{
7432 			float ft = 0.8;
7433 			float nt = 0.1;
7434 			float nt2 = 0.2;
7435 			void *handle = NULL;
7436 
7437 			/*
7438 			if (!longAnim)
7439 			{
7440 				float factor = 0.3;
7441 				ft *= factor;
7442 				nt *= factor;
7443 				nt2 *= factor;
7444 			}
7445 			*/
7446 
7447 			PlaySfx note1;
7448 			note1.name = getNoteName(0);
7449 			PlaySfx note2;
7450 			note2.name = getNoteName(4);
7451 			PlaySfx note3;
7452 			note3.name = getNoteName(3);
7453 
7454 			handle = dsq->sound->playSfx(note1);
7455 			dsq->main(nt2);
7456 			dsq->sound->fadeSfx(handle, SFT_OUT, ft);
7457 			dsq->main(nt);
7458 
7459 			handle = dsq->sound->playSfx(note2);
7460 			dsq->main(nt2);
7461 			dsq->sound->fadeSfx(handle, SFT_OUT, ft);
7462 			dsq->main(nt);
7463 
7464 			handle = dsq->sound->playSfx(note3);
7465 			dsq->main(nt2);
7466 			dsq->sound->fadeSfx(handle, SFT_OUT, ft);
7467 			dsq->main(nt);
7468 		}
7469 
7470 		dsq->sound->playSfx("boil");
7471 
7472 		for (int i = 0; i < foodHolders.size(); i++)
7473 		{
7474 			if (!foodHolders[i]->isEmpty())
7475 				dsq->spawnParticleEffect("cook-ingredient", foodHolders[i]->getWorldPosition(), 0, 0, LR_HUD3, 1);
7476 		}
7477 
7478 		if (longAnim)
7479 			dsq->main(0.5);
7480 		else
7481 			dsq->main(0.2);
7482 
7483 		bool haveLeftovers = true;
7484 		for (int i = 0; i < foodHolders.size(); i++)
7485 		{
7486 			if (!foodHolders[i]->isEmpty()) {
7487 				IngredientData *ing = foodHolders[i]->getIngredient();
7488 				if (!ing || ing->amount < ing->held)
7489 				{
7490 					haveLeftovers = false;
7491 					break;
7492 				}
7493 			}
7494 		}
7495 		for (int i = 0; i < foodHolders.size(); i++)
7496 		{
7497 			IngredientData *ing = foodHolders[i]->getIngredient();
7498 			if (ing)
7499 			{
7500 				ing->amount--;
7501 			}
7502 
7503 			if (!haveLeftovers)
7504 			{
7505 				foodHolders[i]->setIngredient(0, false);
7506 			}
7507 		}
7508 
7509 		dsq->sound->playSfx("Cook");
7510 
7511 		for (int i = 0; i < foodHolders.size(); i++)
7512 			if (foodHolders[i]->alpha.x > 0 && !foodHolders[i]->isTrash())
7513 				foodHolders[i]->animateLid(false);
7514 
7515 		dsq->spawnParticleEffect("cook-food", Vector(575,250), 0, 0, LR_HUD3, 1);
7516 
7517 		if (longAnim)
7518 			dsq->main(0.5);
7519 		else
7520 			dsq->main(0.2);
7521 
7522 		if (data)
7523 		{
7524 			float t = 3;
7525 			std::string n = "Ingredients/" + data->gfx;
7526 			//Quad *e = new Quad();
7527 
7528 			showRecipe->setTexture(n);
7529 			showRecipe->scale = Vector(0.5, 0.5);
7530 			showRecipe->scale.interpolateTo(Vector(1.2, 1.2), t);
7531 			showRecipe->alpha.ensureData();
7532 			showRecipe->alpha.data->path.clear();
7533 			showRecipe->alpha.data->path.addPathNode(0, 0);
7534 			showRecipe->alpha.data->path.addPathNode(1, 0.1);
7535 			showRecipe->alpha.data->path.addPathNode(1, 0.6);
7536 			showRecipe->alpha.data->path.addPathNode(0, 1);
7537 			showRecipe->alpha.startPath(t);
7538 		}
7539 
7540 		dsq->continuity.pickupIngredient(data, 1);
7541 
7542 		dsq->continuity.removeEmptyIngredients();
7543 
7544 		dsq->main(0.5);
7545 
7546 		dsq->continuity.setFlag(FLAG_COOKS, dsq->continuity.getFlag(FLAG_COOKS)+1);
7547 
7548 		if (r)
7549 		{
7550 			dsq->continuity.learnRecipe(r);
7551 			if (haveLeftovers)
7552 				updatePreviewRecipe();
7553 		}
7554 
7555 		core->mouse.buttonsEnabled = true;
7556 	}
7557 	else
7558 	{
7559 		dsq->sound->playSfx("Denied");
7560 		dsq->centerMessage(dsq->continuity.stringBank.get(27));
7561 	}
7562 	refreshFoodSlots(true);
7563 
7564 endcook:
7565 
7566 	AquariaGuiElement::canDirMoveGlobal = true;
7567 
7568 	isCooking = false;
7569 }
7570 
overrideZoom(float sz,float t)7571 void Game::overrideZoom(float sz, float t)
7572 {
7573 	if (sz == 0)
7574 	{
7575 		dsq->game->toggleOverrideZoom(false);
7576 	}
7577 	else
7578 	{
7579 		dsq->game->toggleOverrideZoom(true);
7580 		dsq->globalScale.stop();
7581 		dsq->globalScale.interpolateTo(Vector(sz, sz), t);
7582 		dsq->globalScaleChanged();
7583 	}
7584 }
7585 
getFoodSlotFromIndex()7586 FoodSlot* getFoodSlotFromIndex()
7587 {
7588 	for (int i = 0; i < dsq->game->foodSlots.size(); i++)
7589 	{
7590 		if (dsq->game->foodSlots[i]->slot == FoodSlot::foodSlotIndex)
7591 		{
7592 			return dsq->game->foodSlots[i];
7593 		}
7594 	}
7595 	return 0;
7596 }
7597 
onLips()7598 void Game::onLips()
7599 {
7600 	if (!foodMenu)
7601 	{
7602 		if (dsq->lastVoiceFile.find("NAIJA_SONG_") != std::string::npos)
7603 		{
7604 			dsq->stopVoice();
7605 		}
7606 	}
7607 }
7608 
7609 const float hintTransTime = 0.5;
7610 
clearControlHint()7611 void Game::clearControlHint()
7612 {
7613 	if (!controlHint_ignoreClear)
7614 	{
7615 		controlHintTimer = 0;
7616 
7617 		if (controlHint_bg)
7618 		{
7619 			controlHint_mouseLeft->alpha.interpolateTo(0, hintTransTime);
7620 			controlHint_mouseRight->alpha.interpolateTo(0, hintTransTime);
7621 			controlHint_mouseMiddle->alpha.interpolateTo(0, hintTransTime);
7622 			controlHint_mouseBody->alpha.interpolateTo(0, hintTransTime);
7623 			controlHint_text->alpha.interpolateTo(0, hintTransTime);
7624 			controlHint_bg->alpha.interpolateTo(0, hintTransTime);
7625 			controlHint_image->alpha.interpolateTo(0, hintTransTime);
7626 		}
7627 
7628 		for (int i = 0; i < controlHintNotes.size(); i++)
7629 		{
7630 			controlHintNotes[i]->alpha.interpolateTo(0, hintTransTime);
7631 		}
7632 		controlHintNotes.clear();
7633 	}
7634 }
7635 
getWaterLevel()7636 float Game::getWaterLevel()
7637 {
7638 	return waterLevel.x;
7639 }
7640 
setControlHint(const std::string & h,bool left,bool right,bool middle,float time,std::string image,bool ignoreClear,int songType,float scale)7641 void Game::setControlHint(const std::string &h, bool left, bool right, bool middle, float time, std::string image, bool ignoreClear, int songType, float scale)
7642 {
7643 	if (!h.empty())
7644 		dsq->sound->playSfx("controlhint");
7645 
7646 	controlHint_ignoreClear = false;
7647 	clearControlHint();
7648 	std::string hint = h;
7649 
7650 	controlHintTimer = time;
7651 
7652 	if (core->flipMouseButtons)
7653 	{
7654 		if (h.find("Left")!=std::string::npos && h.find("Right")==std::string::npos)
7655 		{
7656 			std::string sought = "Left";
7657 			std::string replacement = "Right";
7658 			hint.replace(hint.find(sought), sought.size(), replacement);
7659 		}
7660 		else if (h.find("Left")==std::string::npos && h.find("Right")!=std::string::npos)
7661 		{
7662 			std::string sought = "Right";
7663 			std::string replacement = "Left";
7664 			hint.replace(hint.find(sought), sought.size(), replacement);
7665 		}
7666 		std::swap(left, right);
7667 	}
7668 
7669 	std::ostringstream os;
7670 	os << "set control hint: (" << hint << ", " << left << ", " << right << ", " << middle << " t: " << time << " )";
7671 	debugLog(os.str());
7672 
7673 	if (songType > 0)
7674 	{
7675 		//Song *song = getSongByIndex(num);
7676 		Song *song = dsq->continuity.getSongByIndex(songType);
7677 		controlHintNotes.clear();
7678 
7679 		Vector p = controlHint_mouseLeft->position + Vector(-100,0);
7680 
7681 		char sbuf[32];
7682 		sprintf(sbuf, "song/songslot-%d", dsq->continuity.getSongSlotByType(songType));
7683 		Quad *q = new Quad(sbuf, p);
7684 		q->followCamera = 1;
7685 		q->scale = Vector(0.7, 0.7);
7686 		q->alpha = 0;
7687 		addRenderObject(q, controlHint_bg->layer);
7688 		controlHintNotes.push_back(q);
7689 
7690 		p += Vector(100, 0);
7691 
7692 		for (int i = 0; i < song->notes.size(); i++)
7693 		{
7694 			int note = song->notes[i];
7695 
7696 			sprintf(sbuf, "song/notebutton-%d", note);
7697 			Quad *q = new Quad(sbuf, p);
7698 			q->color = dsq->getNoteColor(note)*0.5f + Vector(1, 1, 1)*0.5f;
7699 			q->followCamera = 1;
7700 			q->scale = Vector(1.0, 1.0);
7701 			q->alpha = 0;
7702 
7703 			if (i % 2)
7704 				q->offset = Vector(0, -10);
7705 			else
7706 				q->offset = Vector(0, 10);
7707 
7708 			addRenderObject(q, controlHint_bg->layer);
7709 
7710 			controlHintNotes.push_back(q);
7711 
7712 			p += Vector(40, 0);
7713 		}
7714 	}
7715 
7716 	float alphaOn = 0.8, alphaOff = 0.5;
7717 	controlHint_bg->alpha.interpolateTo(1, hintTransTime);
7718 	controlHint_bg->scale = Vector(1,1);
7719 	//controlHint_bg->scale = Vector(0,1);
7720 	//controlHint_bg->scale.interpolateTo(Vector(1,1), hintTransTime);
7721 	controlHint_text->setText(hint);
7722 	controlHint_text->alpha.interpolateTo(1, hintTransTime);
7723 
7724 	if (!image.empty())
7725 	{
7726 		controlHint_image->setTexture(image);
7727 		controlHint_image->alpha.interpolateTo(1, hintTransTime);
7728 		controlHint_image->scale = Vector(scale, scale);
7729 		//controlHint_image->scale = Vector(0.5, 0.5);
7730 	}
7731 	else
7732 	{
7733 		controlHint_image->alpha.interpolateTo(0, hintTransTime);
7734 	}
7735 
7736 
7737 	controlHint_text->position.x = 400 - controlHint_text->getSetWidth()/2 + 25;
7738 		//400 - controlHint_bg->getWidth()/2 + 25;
7739 	controlHint_text->setAlign(ALIGN_LEFT);
7740 
7741 	if (!left && !right && !middle)
7742 	{
7743 		controlHint_mouseRight->alpha.interpolateTo(0, hintTransTime);
7744 		controlHint_mouseLeft->alpha.interpolateTo(0, hintTransTime);
7745 		controlHint_mouseMiddle->alpha.interpolateTo(0, hintTransTime);
7746 		if (image.empty() && controlHintNotes.empty())
7747 		{
7748 			controlHint_text->position.y = 470;
7749 		}
7750 		else
7751 		{
7752 			controlHint_text->position.y = 520;
7753 			controlHint_text->position.x = 400;
7754 			controlHint_text->setAlign(ALIGN_CENTER);
7755 		}
7756 	}
7757 	else
7758 	{
7759 		controlHint_text->position.y = 520;
7760 		controlHint_text->position.x = 400;
7761 		controlHint_text->setAlign(ALIGN_CENTER);
7762 		if (left)
7763 			controlHint_mouseLeft->alpha.interpolateTo(alphaOn, hintTransTime);
7764 		else
7765 			controlHint_mouseLeft->alpha.interpolateTo(alphaOff, hintTransTime);
7766 
7767 		if (right)
7768 			controlHint_mouseRight->alpha.interpolateTo(alphaOn, hintTransTime);
7769 		else
7770 			controlHint_mouseRight->alpha.interpolateTo(alphaOff, hintTransTime);
7771 
7772 		if (middle)
7773 			controlHint_mouseMiddle->alpha.interpolateTo(alphaOn, hintTransTime);
7774 		else
7775 			controlHint_mouseMiddle->alpha.interpolateTo(alphaOff, hintTransTime);
7776 		controlHint_mouseBody->alpha.interpolateTo(0.5, hintTransTime);
7777 	}
7778 
7779 	for (int i = 0; i < controlHintNotes.size(); i++)
7780 	{
7781 		controlHintNotes[i]->alpha.interpolateTo(alphaOn, hintTransTime);
7782 	}
7783 
7784 	controlHint_ignoreClear = ignoreClear;
7785 
7786 
7787 	controlHint_shine->alpha.ensureData();
7788 	controlHint_shine->alpha.data->path.clear();
7789 	controlHint_shine->alpha.data->path.addPathNode(0.001, 0.0);
7790 	controlHint_shine->alpha.data->path.addPathNode(1.000, 0.3);
7791 	controlHint_shine->alpha.data->path.addPathNode(0.001, 1.0);
7792 	controlHint_shine->alpha.startPath(0.4);
7793 }
7794 
onFlipTest()7795 void Game::onFlipTest()
7796 {
7797 	flipSceneVertical(14960);
7798 }
7799 
appendFileToString(std::string & string,const std::string & file)7800 void appendFileToString(std::string &string, const std::string &file)
7801 {
7802 	InStream inf(file.c_str());
7803 
7804 	if (inf.is_open())
7805 	{
7806 		while (!inf.eof())
7807 		{
7808 			std::string read;
7809 			std::getline(inf, read);
7810 #if BBGE_BUILD_UNIX
7811 			read = stripEndlineForUnix(read);
7812 #endif
7813 			read = dsq->user.control.actionSet.insertInputIntoString(read);
7814 			string += read + "\n";
7815 		}
7816 	}
7817 
7818 	inf.close();
7819 }
7820 
onToggleHelpScreen()7821 void Game::onToggleHelpScreen()
7822 {
7823 	if (inHelpScreen)
7824 		toggleHelpScreen(false);
7825 	else if (core->isStateJumpPending())
7826 		return;
7827 	else
7828 	{
7829 		if (worldMapRender->isOn())
7830 		{
7831 			toggleHelpScreen(true, "[World Map]");
7832 		}
7833 		else if (currentMenuPage == MENUPAGE_FOOD)
7834 		{
7835 			toggleHelpScreen(true, "[Food]");
7836 		}
7837 		else if (currentMenuPage == MENUPAGE_TREASURES)
7838 		{
7839 			toggleHelpScreen(true, "[Treasures]");
7840 		}
7841 		/*
7842 		else if (currentMenuPage == MENUPAGE_SONGS)
7843 		{
7844 			toggleHelpScreen(true, "[Singing]");
7845 		}
7846 		*/
7847 		else if (currentMenuPage == MENUPAGE_PETS)
7848 		{
7849 			toggleHelpScreen(true, "[Pets]");
7850 		}
7851 		else
7852 		{
7853 			toggleHelpScreen(true);
7854 		}
7855 	}
7856 }
7857 
toggleHelpScreen(bool on,const std::string & label)7858 void Game::toggleHelpScreen(bool on, const std::string &label)
7859 {
7860 	if (dsq->game->isSceneEditorActive()) return;
7861 
7862 	if (inHelpScreen == on) return;
7863 	if (core->getShiftState()) return;
7864 	if (dsq->screenTransition->isGoing()) return;
7865 	if (dsq->isNested()) return;
7866 	if (dsq->saveSlotMode != SSM_NONE) return;
7867 
7868 	if (on)
7869 	{
7870 		AquariaGuiElement::currentGuiInputLevel = 100;
7871 		dsq->screenTransition->capture();
7872 
7873 		helpWasPaused = isPaused();
7874 		togglePause(true);
7875 
7876 		std::string data;
7877 
7878 // These say "Mac" but we use them on Linux, too.
7879 #if defined(BBGE_BUILD_UNIX)
7880 		std::string fname = localisePath("data/help_header_mac.txt");
7881 		appendFileToString(data, fname);
7882 #else
7883 		std::string fname = localisePath("data/help_header.txt");
7884 		appendFileToString(data, fname);
7885 #endif
7886 		if (dsq->continuity.hasSong(SONG_BIND)) {
7887 			fname = localisePath("data/help_bindsong.txt");
7888 			appendFileToString(data, fname);
7889 		}
7890 		if (dsq->continuity.hasSong(SONG_ENERGYFORM)) {
7891 			fname = localisePath("data/help_energyform.txt");
7892 			appendFileToString(data, fname);
7893 		}
7894 		fname = localisePath("data/help_start.txt");
7895 		appendFileToString(data, fname);
7896 
7897 // These say "Mac" but we use them on Linux, too.
7898 #if defined(BBGE_BUILD_UNIX)
7899 		fname = localisePath("data/help_end_mac.txt");
7900 		appendFileToString(data, fname);
7901 #else
7902 		fname = localisePath("data/help_end.txt");
7903 		appendFileToString(data, fname);
7904 #endif
7905 
7906 		// !!! FIXME: this is such a hack.
7907 		data += "\n\n" + dsq->continuity.stringBank.get(2032) + "\n\n";
7908 		dsq->continuity.statsAndAchievements->appendStringData(data);
7909 
7910 		helpBG = new Quad;
7911 		//helpBG->color = 0;
7912 		helpBG->setTexture("brick");
7913 		helpBG->repeatTextureToFill(true);
7914 		helpBG->repeatToFillScale = Vector(2, 2);
7915 		//helpBG->alphaMod = 0.75;
7916 		helpBG->autoWidth = AUTO_VIRTUALWIDTH;
7917 		helpBG->autoHeight = AUTO_VIRTUALHEIGHT;
7918 		helpBG->position = Vector(400,300);
7919 		helpBG->followCamera = 1;
7920 		addRenderObject(helpBG, LR_HELP);
7921 
7922 		helpBG2 = new Quad;
7923 		helpBG2->color = 0;
7924 		helpBG2->alphaMod = 0.5;
7925 		helpBG2->setWidth(620);
7926 		helpBG2->autoHeight = AUTO_VIRTUALHEIGHT;
7927 		helpBG2->position = Vector(400,300);
7928 		helpBG2->followCamera = 1;
7929 		addRenderObject(helpBG2, LR_HELP);
7930 
7931 		helpText = new TTFText(&dsq->fontArialSmall);
7932 		//test->setAlign(ALIGN_CENTER);
7933 		helpText->setWidth(600);
7934 		helpText->setText(data);
7935 		//test->setAlign(ALIGN_CENTER);
7936 		helpText->cull = false;
7937 		helpText->followCamera = 1;
7938 		helpText->position = Vector(100, 20);
7939 		if (!label.empty())
7940 		{
7941 			int line = helpText->findLine(label);
7942 			helpText->offset.interpolateTo(Vector(0, -helpText->getLineHeight()*line), -1200);
7943 		}
7944 
7945 		//helpText->offset.interpolateTo(Vector(0, -400), 4, -1, 1);
7946 		//test->position = Vector(400,300);
7947 		addRenderObject(helpText, LR_HELP);
7948 
7949 		helpUp = new AquariaMenuItem;
7950 		helpUp->useQuad("Gui/arrow-left");
7951 		helpUp->useSound("click");
7952 		helpUp->useGlow("particles/glow", 64, 32);
7953 		helpUp->position = Vector(50, 40);
7954 		helpUp->followCamera = 1;
7955 		helpUp->rotation.z = 90;
7956 		helpUp->event.set(MakeFunctionEvent(Game, onHelpUp));
7957 		helpUp->scale = Vector(0.6, 0.6);
7958 		helpUp->guiInputLevel = 100;
7959 		addRenderObject(helpUp, LR_HELP);
7960 
7961 		helpDown = new AquariaMenuItem;
7962 		helpDown->useQuad("Gui/arrow-right");
7963 		helpDown->useSound("click");
7964 		helpDown->useGlow("particles/glow", 64, 32);
7965 		helpDown->position = Vector(50, 600-40);
7966 		helpDown->followCamera = 1;
7967 		helpDown->rotation.z = 90;
7968 		helpDown->event.set(MakeFunctionEvent(Game, onHelpDown));
7969 		helpDown->scale = Vector(0.6, 0.6);
7970 		helpDown->guiInputLevel = 100;
7971 		addRenderObject(helpDown, LR_HELP);
7972 
7973 		helpCancel = new AquariaMenuItem;
7974 		helpCancel->useQuad("Gui/cancel");
7975 		helpCancel->useSound("click");
7976 		helpCancel->useGlow("particles/glow", 128, 40);
7977 		helpCancel->position = Vector(750, 600-20);
7978 		helpCancel->followCamera = 1;
7979 		//helpCancel->rotation.z = 90;
7980 		helpCancel->event.set(MakeFunctionEvent(Game, toggleHelpScreen));
7981 		helpCancel->scale = Vector(0.9, 0.9);
7982 		helpCancel->guiInputLevel = 100;
7983 		addRenderObject(helpCancel, LR_HELP);
7984 
7985 		for (int i = 0; i < LR_HELP; i++)
7986 		{
7987 			core->getRenderObjectLayer(i)->visible = false;
7988 		}
7989 
7990 		core->resetTimer();
7991 
7992 		dsq->screenTransition->transition(MENUPAGETRANSTIME);
7993 	}
7994 	else
7995 	{
7996 		if (!helpWasPaused)
7997 			togglePause(false);
7998 		dsq->screenTransition->capture();
7999 		if (helpText)
8000 		{
8001 			helpText->alpha = 0;
8002 			helpText->setLife(1);
8003 			helpText->setDecayRate(1000);
8004 			helpText = 0;
8005 		}
8006 		if (helpBG)
8007 		{
8008 			helpBG->alpha = 0;
8009 			helpBG->setLife(1);
8010 			helpBG->setDecayRate(1000);
8011 			helpBG = 0;
8012 		}
8013 		if (helpBG2)
8014 		{
8015 			helpBG2->alpha = 0;
8016 			helpBG2->setLife(1);
8017 			helpBG2->setDecayRate(1000);
8018 			helpBG2 = 0;
8019 		}
8020 		if (helpUp)
8021 		{
8022 			helpUp->alpha = 0;
8023 			helpUp->setLife(1);
8024 			helpUp->setDecayRate(1000);
8025 			helpUp = 0;
8026 		}
8027 		if (helpDown)
8028 		{
8029 			helpDown->alpha = 0;
8030 			helpDown->setLife(1);
8031 			helpDown->setDecayRate(1000);
8032 			helpDown = 0;
8033 		}
8034 		if (helpCancel)
8035 		{
8036 			helpCancel->alpha = 0;
8037 			helpCancel->setLife(1);
8038 			helpCancel->setDecayRate(1000);
8039 			helpCancel = 0;
8040 		}
8041 
8042 		for (int i = 0; i < LR_HELP; i++)
8043 		{
8044 			core->getRenderObjectLayer(i)->visible = true;
8045 		}
8046 		dsq->applyParallaxUserSettings();
8047 
8048 		dsq->screenTransition->transition(MENUPAGETRANSTIME);
8049 
8050 
8051 		AquariaGuiElement::currentGuiInputLevel = 0;
8052 	}
8053 
8054 	inHelpScreen = on;
8055 }
updateMusic()8056 bool Game::updateMusic()
8057 {
8058 	std::string musicToPlay = this->musicToPlay;
8059 	if (!overrideMusic.empty())
8060 	{
8061 		musicToPlay = overrideMusic;
8062 	}
8063 
8064 	if (!musicToPlay.empty())
8065 	{
8066 		if (musicToPlay == "none")
8067 			core->sound->fadeMusic(SFT_OUT, 1);
8068 		else
8069 		{
8070 			bool play = true;
8071 			/*
8072 			std::string originalFile = musicToPlay;
8073 			std::string file = originalFile;
8074 
8075 			if (!exists(file, false) && file.find('.') == std::string::npos)
8076 			{
8077 				file = originalFile + ".ogg";
8078 				if (!exists(file, false))
8079 				{
8080 					file = originalFile + ".mp3";
8081 					if (!exists(file, false))
8082 					{
8083 						errorLog ("music file not found [" + originalFile + "]");
8084 						play = false;
8085 					}
8086 				}
8087 			}
8088 			*/
8089 			if (play)
8090 			{
8091 				/*
8092 				if (core->sound->isStreamingMusic())
8093 					core->sound->crossfadeOutMusic(1);
8094 				*/
8095 				return core->sound->playMusic(musicToPlay, SLT_LOOP, SFT_CROSS, 1, SCT_ISNOTPLAYING);
8096 			}
8097 		}
8098 	}
8099 	else
8100 	{
8101 		core->sound->fadeMusic(SFT_OUT, 1);
8102 	}
8103 	return false;
8104 }
8105 
onPressEscape()8106 void Game::onPressEscape()
8107 {
8108 	if (dsq->isInCutscene())
8109 	{
8110 		// do nothing (moved to dsq::
8111 	}
8112 	else
8113 	{
8114 		if (inHelpScreen)
8115 		{
8116 			toggleHelpScreen(false);
8117 			return;
8118 		}
8119 		if (dsq->game->worldMapRender->isOn() && !dsq->isNested())
8120 		{
8121 			dsq->game->worldMapRender->toggle(false);
8122 			return;
8123 		}
8124 		if (dsq->game->isInGameMenu())
8125 		{
8126 			if (!AquariaKeyConfig::waitingForInput)
8127 			{
8128 				if (dsq->game->menuOpenTimer > 0.5f)
8129 				{
8130 					if (optionsMenu || keyConfigMenu)
8131 						onOptionsCancel();
8132 					else
8133 						action(ACTION_TOGGLEMENU, 0); // hide menu
8134 				}
8135 			}
8136 			return;
8137 		}
8138 
8139 		if (!paused)
8140 		{
8141 			if (core->getNestedMains() == 1 && !core->isStateJumpPending())
8142 				action(ACTION_TOGGLEMENU, 1); // show menu
8143 		}
8144 		else
8145 		{
8146 
8147 			if (autoMap)
8148 			{
8149 				if (paused && autoMap->isOn())
8150 					autoMap->toggle(false);
8151 			}
8152 		}
8153 
8154 
8155 		if ((dsq->saveSlotMode != SSM_NONE || dsq->inModSelector) && core->isNested())
8156 		{
8157 			dsq->selectedSaveSlot = 0;
8158 			core->quitNestedMain();
8159 		}
8160 	}
8161 }
8162 
onDebugSave()8163 void Game::onDebugSave()
8164 {
8165 	hideInGameMenu();
8166 	clearControlHint();
8167 	core->main(0.5);
8168 	dsq->game->togglePause(true);
8169 	dsq->doSaveSlotMenu(SSM_SAVE);
8170 	dsq->game->togglePause(false);
8171 	//dsq->continuity.saveFile(0);
8172 }
8173 
onInGameMenuInventory()8174 void Game::onInGameMenuInventory()
8175 {
8176 }
8177 
onInGameMenuSpellBook()8178 void Game::onInGameMenuSpellBook()
8179 {
8180 }
8181 
onInGameMenuContinue()8182 void Game::onInGameMenuContinue()
8183 {
8184 	hideInGameMenu();
8185 }
8186 
onInGameMenuOptions()8187 void Game::onInGameMenuOptions()
8188 {
8189 }
8190 
onInGameMenuSave()8191 void Game::onInGameMenuSave()
8192 {
8193 }
8194 
onExitCheckYes()8195 void Game::onExitCheckYes()
8196 {
8197 	dsq->sound->stopAllVoice();
8198 	dsq->toggleCursor(0, 0.25);
8199 	dsq->title();
8200 }
8201 
onExitCheckNo()8202 void Game::onExitCheckNo()
8203 {
8204 	hideInGameMenuExitCheck(true);
8205 }
8206 
showInGameMenuExitCheck()8207 void Game::showInGameMenuExitCheck()
8208 {
8209 	recipeMenu.toggle(false);
8210 	inGameMenuExitState = 1;
8211 	eYes->alpha.interpolateTo(1, 0.2);
8212 	eNo->alpha.interpolateTo(1, 0.2);
8213 	eAre->alpha.interpolateTo(1, 0.2);
8214 
8215 	eNo->setFocus(true);
8216 }
8217 
hideInGameMenuExitCheck(bool refocus)8218 void Game::hideInGameMenuExitCheck(bool refocus)
8219 {
8220 	inGameMenuExitState = 0;
8221 	eYes->alpha.interpolateTo(0, 0.2);
8222 	eNo->alpha.interpolateTo(0, 0.2);
8223 	eAre->alpha.interpolateTo(0, 0.2);
8224 
8225 	if (refocus)
8226 		((AquariaMenuItem*)menu[1])->setFocus(true);
8227 }
8228 
onInGameMenuExit()8229 void Game::onInGameMenuExit()
8230 {
8231 	if (!dsq->user.demo.warpKeys || (core->getCtrlState() && core->getAltState()))
8232 	{
8233 		if (inGameMenuExitState == 0)
8234 		{
8235 			// show yes/no
8236 			showInGameMenuExitCheck();
8237 		}
8238 	}
8239 }
8240 
toggleDamageSprite(bool on)8241 void Game::toggleDamageSprite(bool on)
8242 {
8243 	if (on)
8244 	{
8245 		damageSprite->alphaMod = 1;
8246 	}
8247 	else
8248 		damageSprite->alphaMod = 0;
8249 }
8250 
togglePause(bool v)8251 void Game::togglePause(bool v)
8252 {
8253 	paused = v;
8254 	if (paused)
8255 	{
8256 		dsq->cursorGlow->alpha		= 0;
8257 		dsq->cursorBlinker->alpha	= 0;
8258 		//dsq->overlay->alpha.interpolateTo(0.5, 0.5);
8259 	}
8260 	//core->particlesPaused = v;
8261 	/*
8262 	else
8263 		dsq->overlay->alpha.interpolateTo(0, 0.5);
8264 		*/
8265 }
8266 
isPaused()8267 bool Game::isPaused()
8268 {
8269 	return paused;
8270 }
8271 
playBurstSound(bool wallJump)8272 void Game::playBurstSound(bool wallJump)
8273 {
8274 	int freqBase = 950;
8275 	if (wallJump)
8276 		freqBase += 100;
8277 	sound->playSfx("Burst", 1);
8278 	if (chance(50))
8279 	{
8280 		switch (dsq->continuity.form)
8281 		{
8282 		case FORM_BEAST:
8283 			sound->playSfx("BeastBurst", (128+rand()%64)/256.0f);
8284 		break;
8285 		}
8286 	}
8287 }
8288 
collideCircleVsCircle(Entity * a,Entity * b)8289 bool Game::collideCircleVsCircle(Entity *a, Entity *b)
8290 {
8291 	return (a->position - b->position).isLength2DIn(a->collideRadius + b->collideRadius);
8292 }
8293 
collideHairVsCircle(Entity * a,int num,const Vector & pos2,float radius,float perc,int * colSegment)8294 bool Game::collideHairVsCircle(Entity *a, int num, const Vector &pos2, float radius, float perc, int *colSegment)
8295 {
8296 	if (perc == 0)
8297 		perc = 1;
8298 	bool c = false;
8299 	if (a && a->hair)
8300 	{
8301 		if (num == 0)
8302 			num = a->hair->hairNodes.size();
8303 		// HACK: minus 2
8304 		for (int i = 0; i < num; i++)
8305 		{
8306 			// + a->hair->position
8307 			c = ((a->hair->hairNodes[i].position) - pos2).isLength2DIn(a->hair->hairWidth*perc + radius);
8308 			if (c)
8309 			{
8310 				if (colSegment)
8311 					*colSegment = i;
8312 				return true;
8313 			}
8314 		}
8315 	}
8316 	return c;
8317 }
8318 
8319 // NOTE THIS FUNCTION ASSUMES THAT IF A BONE ISN'T AT FULL ALPHA (1.0) IT IS DISABLED
collideSkeletalVsCircle(Entity * skeletal,RenderObject * circle)8320 Bone *Game::collideSkeletalVsCircle(Entity *skeletal, RenderObject *circle)
8321 {
8322 	return collideSkeletalVsCircle(skeletal, circle->position, circle->collideRadius);
8323 }
8324 
collideSkeletalVsLine(Entity * skeletal,Vector start,Vector end,float radius)8325 Bone *Game::collideSkeletalVsLine(Entity *skeletal, Vector start, Vector end, float radius)
8326 {
8327 	//float smallestDist = HUGE_VALF;
8328 	Bone *closest = 0;
8329 	for (int i = 0; i < skeletal->skeletalSprite.bones.size(); i++)
8330 	{
8331 		Bone *b = skeletal->skeletalSprite.bones[i];
8332 		/*
8333 		int checkRadius = sqr(radius+b->collisionMaskRadius);
8334 		Vector bonePos = b->getWorldCollidePosition();
8335 		float dist = (bonePos - pos).getSquaredLength2D();
8336 		*/
8337 
8338 		// MULTIPLE CIRCLES METHOD
8339 		if (!b->collisionMask.empty() && b->alpha.x == 1 && b->renderQuad)
8340 		{
8341 			for (int i = 0; i < b->transformedCollisionMask.size(); i++)
8342 			{
8343 				if (isTouchingLine(start, end, b->transformedCollisionMask[i], radius+b->collideRadius))
8344 				{
8345 					closest = b;
8346 					//smallestDist = dist;
8347 					break;
8348 				}
8349 			}
8350 		}
8351 		if (closest != 0)
8352 		{
8353 			break;
8354 		}
8355 		/*
8356 		// ONE CIRCLE PER BONE METHOD
8357 		else if (b->collideRadius && b->alpha.x == 1)
8358 		{
8359 			if (dist < checkRadius)
8360 			{
8361 				if (dist < smallestDist)
8362 				{
8363 					closest = b;
8364 					smallestDist = dist;
8365 				}
8366 			}
8367 		}
8368 		*/
8369 	}
8370 	return closest;
8371 }
8372 
collideCircleVsLine(RenderObject * r,Vector start,Vector end,float radius)8373 bool Game::collideCircleVsLine(RenderObject *r, Vector start, Vector end, float radius)
8374 {
8375 	bool collision = false;
8376 	if (isTouchingLine(start, end, r->position, radius+r->collideRadius, &lastCollidePosition))
8377 	{
8378 		collision = true;
8379 	}
8380 	return collision;
8381 }
8382 
collideCircleVsLineAngle(RenderObject * r,float angle,float startLen,float endLen,float radius,Vector basePos)8383 bool Game::collideCircleVsLineAngle(RenderObject *r, float angle, float startLen, float endLen, float radius, Vector basePos)
8384 {
8385 	bool collision = false;
8386 	float rads = MathFunctions::toRadians(angle);
8387 	float sinv = sinf(rads);
8388 	float cosv = cosf(rads);
8389 	Vector start=Vector(sinv,cosv)*startLen + basePos;
8390 	Vector end=Vector(sinv,cosv)*endLen + basePos;
8391 	if (isTouchingLine(start, end, r->position, radius+r->collideRadius, &lastCollidePosition))
8392 	{
8393 		collision = true;
8394 	}
8395 	if (shapeDebug)
8396 	{
8397 		shapeDebug->position = end;
8398 	}
8399 	return collision;
8400 }
8401 
8402 
collideSkeletalVsCircle(Entity * skeletal,Vector pos,float radius)8403 Bone *Game::collideSkeletalVsCircle(Entity *skeletal, Vector pos, float radius)
8404 {
8405 	float smallestDist = HUGE_VALF;
8406 	Bone *closest = 0;
8407 	if (!(pos - skeletal->position).isLength2DIn(2000)) return 0;
8408 	for (int i = 0; i < skeletal->skeletalSprite.bones.size(); i++)
8409 	{
8410 		Bone *b = skeletal->skeletalSprite.bones[i];
8411 
8412 		if (b->alpha.x == 1 && b->renderQuad)
8413 		{
8414 			float checkRadius = sqr(radius+b->collisionMaskRadius);
8415 			Vector bonePos = b->getWorldCollidePosition();
8416 			float dist = (bonePos - pos).getSquaredLength2D();
8417 			// BOUND RECT METHOD
8418 			if (!b->collisionRects.empty())
8419 			{
8420 				for (int i = 0; i < b->collisionRects.size(); i++)
8421 				{
8422 					b->collisionRects[i].isCoordinateInside(pos, radius);
8423 				}
8424 			}
8425 			// MULTIPLE CIRCLES METHOD
8426 			else if (!b->collisionMask.empty())
8427 			{
8428 				if (dist < checkRadius)
8429 				{
8430 					for (int i = 0; i < b->transformedCollisionMask.size(); i++)
8431 					{
8432 						if ((b->transformedCollisionMask[i] - pos).isLength2DIn(radius+b->collideRadius*skeletal->scale.x))
8433 						{
8434 							closest = b;
8435 							smallestDist = dist;
8436 							lastCollideMaskIndex = i;
8437 							break;
8438 						}
8439 					}
8440 				}
8441 			}
8442 			// ONE CIRCLE PER BONE METHOD
8443 			else if (b->collideRadius)
8444 			{
8445 				if (dist < sqr(radius+b->collideRadius))
8446 				{
8447 					if (dist < smallestDist)
8448 					{
8449 						closest = b;
8450 						smallestDist = dist;
8451 					}
8452 				}
8453 			}
8454 		}
8455 	}
8456 	return closest;
8457 }
8458 
preLocalWarp(LocalWarpType localWarpType)8459 void Game::preLocalWarp(LocalWarpType localWarpType)
8460 {
8461 	// won't work if you start the map inside a local warp area... but that doesn't happen much for collecting gems
8462 	if (localWarpType == LOCALWARP_IN)
8463 	{
8464 		dsq->game->avatar->warpInLocal = dsq->game->avatar->position;
8465 	}
8466 	else if (localWarpType == LOCALWARP_OUT)
8467 	{
8468 		dsq->game->avatar->warpInLocal = Vector(0,0,0);
8469 	}
8470 
8471 	dsq->screenTransition->capture();
8472 	core->resetTimer();
8473 }
8474 
postLocalWarp()8475 void Game::postLocalWarp()
8476 {
8477 	if (dsq->game->li && dsq->continuity.hasLi())
8478 		dsq->game->li->position = dsq->game->avatar->position;
8479 	if (dsq->game->avatar->pullTarget)
8480 		dsq->game->avatar->pullTarget->position = dsq->game->avatar->position;
8481 	dsq->game->snapCam();
8482 	dsq->screenTransition->transition(0.6);
8483 
8484 }
8485 
registerSporeDrop(const Vector & pos,int t)8486 void Game::registerSporeDrop(const Vector &pos, int t)
8487 {
8488 	FOR_ENTITIES(i)
8489 	{
8490 		Entity *e = *i;
8491 		if ((e->position - pos).isLength2DIn(1024))
8492 		{
8493 			e->sporesDropped(pos, t);
8494 		}
8495 	}
8496 }
8497 
isEntityCollideWithShot(Entity * e,Shot * shot)8498 bool Game::isEntityCollideWithShot(Entity *e, Shot *shot)
8499 {
8500 	if (!shot->isHitEnts() || shot->firer == e)
8501 	{
8502 		return false;
8503 	}
8504 	if (shot->checkDamageTarget)
8505 	{
8506 		if (!e->isDamageTarget(shot->getDamageType()))
8507 			return false;
8508 	}
8509 	if (e->getEntityType() == ET_ENEMY)
8510 	{
8511 		if (shot->getDamageType() == DT_AVATAR_BITE)
8512 		{
8513 			Avatar::BittenEntities::iterator i;
8514 			for (i = avatar->bittenEntities.begin(); i != avatar->bittenEntities.end(); i++)
8515 			{
8516 				if (e == (*i))
8517 				{
8518 					return false;
8519 				}
8520 			}
8521 			return true;
8522 		}
8523 	}
8524 	else if (e->getEntityType() == ET_AVATAR)
8525 	{
8526 		// this used to be stuff != ET_AVATAR.. but what else would do that
8527 		return !dsq->game->isDamageTypeAvatar(shot->getDamageType()) && (!shot->firer || shot->firer->getEntityType() == ET_ENEMY);
8528 	}
8529 	else if (e->getEntityType() == ET_PET)
8530 	{
8531 		bool go = shot->firer != e;
8532 		if (shot->firer && shot->firer->getEntityType() != ET_ENEMY)
8533 			go = false;
8534 		return go;
8535 	}
8536 
8537 	return true;
8538 }
8539 
handleShotCollisions(Entity * e,bool hasShield)8540 void Game::handleShotCollisions(Entity *e, bool hasShield)
8541 {
8542 	BBGE_PROF(Game_handleShotCollisions);
8543 	for (size_t i = 0; i < Shot::shots.size(); ++i)
8544 	{
8545 		Shot *shot = Shot::shots[i];
8546 		if (shot->isActive() && isEntityCollideWithShot(e, shot) && (!hasShield || (!shot->shotData || !shot->shotData->ignoreShield)))
8547 		{
8548 			Vector collidePoint = e->position+e->offset;
8549 			if (e->getNumTargetPoints()>0)
8550 			{
8551 				collidePoint = e->getTargetPoint(0);
8552 			}
8553 			if ((collidePoint - shot->position).isLength2DIn(shot->collideRadius + e->collideRadius))
8554 			{
8555 				lastCollidePosition = shot->position;
8556 				shot->hitEntity(e,0);
8557 			}
8558 		}
8559 	}
8560 }
8561 
isDamageTypeAvatar(DamageType dt)8562 bool Game::isDamageTypeAvatar(DamageType dt)
8563 {
8564 	return (dt >= DT_AVATAR && dt < DT_TOUCH);
8565 }
8566 
isDamageTypeEnemy(DamageType dt)8567 bool Game::isDamageTypeEnemy(DamageType dt)
8568 {
8569 	return (dt >= DT_ENEMY && dt < DT_AVATAR);
8570 }
8571 
handleShotCollisionsSkeletal(Entity * e)8572 void Game::handleShotCollisionsSkeletal(Entity *e)
8573 {
8574 	BBGE_PROF(Game_HSSKELETAL);
8575 	for (size_t i = 0; i < Shot::shots.size(); ++i)
8576 	{
8577 		Shot *shot = Shot::shots[i];
8578 		if (shot->isActive() && isEntityCollideWithShot(e, shot))
8579 		{
8580 			Bone *b = collideSkeletalVsCircle(e, shot->position, shot->collideRadius);
8581 			if (b)
8582 			{
8583 				lastCollidePosition = shot->position;
8584 				shot->hitEntity(e, b);
8585 			}
8586 		}
8587 	}
8588 }
8589 
handleShotCollisionsHair(Entity * e,int num,float perc)8590 void Game::handleShotCollisionsHair(Entity *e, int num, float perc)
8591 {
8592 	for (size_t i = 0; i < Shot::shots.size(); ++i)
8593 	{
8594 		Shot *shot = Shot::shots[i];
8595 		if (shot->isActive() && isEntityCollideWithShot(e, shot))
8596 		{
8597 			bool b = collideHairVsCircle(e, num, shot->position, 8, perc);
8598 			if (b)
8599 			{
8600 				lastCollidePosition = shot->position;
8601 				shot->hitEntity(e, 0);
8602 			}
8603 		}
8604 	}
8605 }
8606 
8607 #ifdef AQUARIA_BUILD_SCENEEDITOR
toggleSceneEditor()8608 void Game::toggleSceneEditor()
8609 {
8610 	if (!core->getAltState())
8611 	{
8612 		sceneEditor.toggle();
8613 		setElementLayerFlags();
8614 	}
8615 }
8616 #endif
8617 
toggleMiniMapRender()8618 void Game::toggleMiniMapRender()
8619 {
8620 	if (miniMapRender)
8621 	{
8622 		if (miniMapRender->alpha == 0)
8623 			miniMapRender->alpha.interpolateTo(1, 0.1f);
8624 		else if (!miniMapRender->alpha.isInterpolating())
8625 			miniMapRender->alpha.interpolateTo(0, 0.1f);
8626 	}
8627 }
8628 
8629 
toggleMiniMapRender(int v)8630 void Game::toggleMiniMapRender(int v)
8631 {
8632 	if (miniMapRender)
8633 	{
8634 		if (v == 0)
8635 			miniMapRender->alpha.interpolateTo(0, 0.1f);
8636 		else
8637 			miniMapRender->alpha.interpolateTo(1, 0.1f);
8638 	}
8639 }
8640 
toggleGridRender()8641 void Game::toggleGridRender()
8642 {
8643 	float t = 0;
8644 	float a = 0;
8645 	if (gridRender->alpha == 0)
8646 		a = 0.5f;
8647 
8648 	gridRender->alpha.interpolateTo(a, t);
8649 	gridRender2->alpha.interpolateTo(a, t);
8650 	gridRender3->alpha.interpolateTo(a, t);
8651 	edgeRender->alpha.interpolateTo(a, t);
8652 	gridRenderEnt->alpha.interpolateTo(a, t);
8653 	gridRenderUser1->alpha.interpolateTo(a, t);
8654 	gridRenderUser2->alpha.interpolateTo(a, t);
8655 }
8656 
getCameraPositionFor(const Vector & pos)8657 Vector Game::getCameraPositionFor(const Vector &pos)
8658 {
8659 	return Vector(pos.x - 400 * core->invGlobalScale, pos.y - 300 * core->invGlobalScale, 0);
8660 }
8661 
setParallaxTextureCoordinates(Quad * q,float speed)8662 void Game::setParallaxTextureCoordinates(Quad *q, float speed)
8663 {
8664 	//int backgroundImageRepeat = 1.2;
8665 	q->followCamera = 1;
8666 	q->texture->repeat = true;
8667 
8668 	float camx = (core->cameraPos.x/800.0f)*speed;
8669 	float camy = -(core->cameraPos.y/600.0f)*speed;
8670 
8671 	float camx1 = camx - float(backgroundImageRepeat)/2.0f;
8672 	float camx2 = camx + float(backgroundImageRepeat)/2.0f;
8673 	float camy1 = camy - float(backgroundImageRepeat)/2.0f;
8674 	float camy2 = camy + float(backgroundImageRepeat)/2.0f;
8675 
8676 	q->upperLeftTextureCoordinates = Vector(camx1*backgroundImageRepeat, camy1*backgroundImageRepeat);
8677 	q->lowerRightTextureCoordinates = Vector(camx2*backgroundImageRepeat, camy2*backgroundImageRepeat);
8678 }
8679 
setCameraFollow(Vector * position)8680 void Game::setCameraFollow(Vector *position)
8681 {
8682 	cameraFollow = position;
8683 	cameraFollowObject = 0;
8684 	cameraFollowEntity = 0;
8685 }
8686 
setCameraFollow(RenderObject * r)8687 void Game::setCameraFollow(RenderObject *r)
8688 {
8689 	cameraFollow = &r->position;
8690 	cameraFollowObject = r;
8691 	cameraFollowEntity = 0;
8692 }
8693 
setCameraFollowEntity(Entity * e)8694 void Game::setCameraFollowEntity(Entity *e)
8695 {
8696 	cameraFollow = &e->position;
8697 	cameraFollowObject = 0;
8698 	cameraFollowEntity = e;
8699 }
8700 
updateCurrentVisuals(float dt)8701 void Game::updateCurrentVisuals(float dt)
8702 {
8703 	/*
8704 	static float delay = 0;
8705 	delay += dt;
8706 	if (delay > 0.2f)
8707 	{
8708 		for (Path *p = dsq->game->getFirstPathOfType(PATH_CURRENT); p; p = p->nextOfType)
8709 		{
8710 			if (p->active)
8711 			{
8712 				for (int n = 1; n < p->nodes.size(); n++)
8713 				{
8714 					PathNode *node2 = &p->nodes[n];
8715 					PathNode *node1 = &p->nodes[n-1];
8716 					Vector dir = node2->position - node1->position;
8717 
8718 					dir.setLength2D(p->currentMod);
8719 					dsq->spawnBubble(node1->position, dir);
8720 				}
8721 			}
8722 
8723 		}
8724 		delay = 0;
8725 	}
8726 	*/
8727 
8728 	/*
8729     if (dsq->game->getPath(i)->name == "CURRENT" && dsq->game->getPath(i)->nodes.size() >= 2)
8730 	{
8731 		Vector dir = dsq->game->getPath(i)->nodes[1].position - dsq->game->getPath(i)->nodes[0].position;
8732 		dir.setLength2D(800);
8733 		dsq->spawnBubble(dsq->game->getPath(i)->nodes[0].position, dir);
8734 	}
8735 	*/
8736 }
8737 
onOptionsMenu()8738 void Game::onOptionsMenu()
8739 {
8740 	dsq->screenTransition->capture();
8741 	toggleOptionsMenu(true);
8742 	dsq->screenTransition->transition(MENUPAGETRANSTIME);
8743 }
8744 
onOptionsSave()8745 void Game::onOptionsSave()
8746 {
8747 	dsq->user.apply();
8748 
8749 	if (dsq->user.video.resx != dsq->user_backup.video.resx
8750 		|| dsq->user.video.resy != dsq->user_backup.video.resy
8751 		|| dsq->user.video.bits != dsq->user_backup.video.bits
8752 		|| dsq->user.video.full != dsq->user_backup.video.full
8753 		|| dsq->user.video.vsync != dsq->user_backup.video.vsync)
8754 	{
8755 		dsq->resetGraphics(dsq->user.video.resx, dsq->user.video.resy, dsq->user.video.full);
8756 		if (dsq->confirm("", "graphics", false, 10)) {
8757 		} else {
8758 			dsq->user.video.resx = dsq->user_backup.video.resx;
8759 			dsq->user.video.resy = dsq->user_backup.video.resy;
8760 			dsq->user.video.bits = dsq->user_backup.video.bits;
8761 			dsq->user.video.full = dsq->user_backup.video.full;
8762 			dsq->user.video.vsync = dsq->user_backup.video.vsync;
8763 
8764 			dsq->user.apply();
8765 
8766 			dsq->resetGraphics(dsq->user.video.resx, dsq->user.video.resy, dsq->user.video.full);
8767 		}
8768 	}
8769 
8770 	/*
8771 	if (dsq->user.video.ripples != dsq->user_backup.video.ripples)
8772 	{
8773 		if (dsq->user.video.ripples)
8774 		{
8775 			if (core->frameBuffer.isInited())
8776 			{
8777 				if (!core->afterEffectManager)
8778 				{
8779 					core->afterEffectManager = new AfterEffectManager(vars->afterEffectsXDivs, vars->afterEffectsYDivs);
8780 					core->afterEffectManager->update(0.0);
8781 					core->afterEffectManager->capture();
8782 				}
8783 
8784 				dsq->useFrameBuffer = 1;
8785 			}
8786 			else
8787 			{
8788 				dsq->useFrameBuffer = 0;
8789 			}
8790 		}
8791 		else
8792 		{
8793 			if (core->afterEffectManager)
8794 			{
8795 				delete core->afterEffectManager;
8796 				core->afterEffectManager = 0;
8797 			}
8798 		}
8799 	}
8800 	*/
8801 
8802 	if (!keyConfigMenu)
8803 		dsq->user.save();
8804 
8805 	if (keyConfigMenu)
8806 	{
8807 		AquariaKeyConfig::waitingForInput = 0;
8808 		dsq->screenTransition->capture();
8809 		toggleKeyConfigMenu(false);
8810 		toggleOptionsMenu(true, false, true);
8811 		dsq->screenTransition->transition(MENUPAGETRANSTIME);
8812 	}
8813 	else
8814 	{
8815 		if (optionsOnly)
8816 		{
8817 			hideInGameMenu();
8818 		}
8819 		else
8820 		{
8821 			dsq->screenTransition->capture();
8822 			toggleOptionsMenu(false);
8823 			dsq->screenTransition->transition(MENUPAGETRANSTIME);
8824 		}
8825 	}
8826 }
8827 
onOptionsCancel()8828 void Game::onOptionsCancel()
8829 {
8830 	if (!keyConfigMenu)
8831 	{
8832 		dsq->user = dsq->user_backup;
8833 	}
8834 	else
8835 	{
8836 		dsq->user.control.actionSet = dsq->user_bcontrol.control.actionSet;
8837 	}
8838 
8839 	dsq->user.apply();
8840 
8841 	if (keyConfigMenu)
8842 	{
8843 		AquariaKeyConfig::waitingForInput = 0;
8844 		dsq->screenTransition->capture();
8845 		toggleKeyConfigMenu(false);
8846 		toggleOptionsMenu(true, true, true);
8847 		dsq->screenTransition->transition(MENUPAGETRANSTIME);
8848 	}
8849 	else
8850 	{
8851 		if (optionsOnly)
8852 		{
8853 			hideInGameMenu();
8854 		}
8855 		else
8856 		{
8857 			dsq->screenTransition->capture();
8858 			toggleOptionsMenu(false);
8859 			dsq->screenTransition->transition(MENUPAGETRANSTIME);
8860 		}
8861 	}
8862 }
8863 
refreshFoodSlots(bool effects)8864 void Game::refreshFoodSlots(bool effects)
8865 {
8866 	for (int i = 0; i < foodSlots.size(); i++)
8867 	{
8868 		foodSlots[i]->refresh(effects);
8869 	}
8870 }
8871 
refreshTreasureSlots()8872 void Game::refreshTreasureSlots()
8873 {
8874 	for (int i = 0; i < treasureSlots.size(); i++)
8875 	{
8876 		treasureSlots[i]->refresh();
8877 	}
8878 }
8879 
togglePetMenu(bool f)8880 void Game::togglePetMenu(bool f)
8881 {
8882 	if (optionsMenu)
8883 	{
8884 		toggleOptionsMenu(false);
8885 	}
8886 
8887 	if (foodMenu)
8888 		toggleFoodMenu(false);
8889 	if (treasureMenu)
8890 		toggleTreasureMenu(false);
8891 
8892 	if (f && !petMenu)
8893 	{
8894 		currentMenuPage = MENUPAGE_PETS;
8895 
8896 		toggleMainMenu(false);
8897 
8898 		bool hasPet = false;
8899 		for (int i = 0; i < petSlots.size(); i++)
8900 		{
8901 			petSlots[i]->alpha = 1;
8902 			bool has = dsq->continuity.getFlag(petSlots[i]->petFlag);
8903 			if (has)
8904 			{
8905 				hasPet = true;
8906 				/*
8907 				for (int j = 0; j < petSlots.size(); j++)
8908 				{
8909 					if (j != i)
8910 					{
8911 						bool has = dsq->continuity.getFlag(petSlots[j]->petFlag);
8912 						if (has)
8913 						{
8914 							if (i == 0 && j == 1)
8915 							{
8916 
8917 							}
8918 						}
8919 					}
8920 				}
8921 				*/
8922 			}
8923 		}
8924 		// act as if they're all active for now...
8925 		if (petSlots.size() == 4)
8926 		{
8927 			petSlots[0]->setDirMove(DIR_RIGHT, petSlots[1]);
8928 			petSlots[0]->setDirMove(DIR_UP, petSlots[2]);
8929 			petSlots[0]->setDirMove(DIR_LEFT, petSlots[3]);
8930 			petSlots[0]->setDirMove(DIR_DOWN, menu[0]);
8931 
8932 			menu[0]->setDirMove(DIR_UP, petSlots[0]);
8933 
8934 			petSlots[1]->setDirMove(DIR_LEFT, petSlots[3]);
8935 			petSlots[1]->setDirMove(DIR_UP, petSlots[2]);
8936 			petSlots[1]->setDirMove(DIR_DOWN, petSlots[0]);
8937 
8938 			petSlots[1]->setDirMove(DIR_RIGHT, menu[5]);
8939 			menu[5]->setDirMove(DIR_LEFT, petSlots[1]);
8940 			menu[5]->setDirMove(DIR_UP, petSlots[1]);
8941 
8942 			petSlots[2]->setDirMove(DIR_RIGHT, petSlots[1]);
8943 			petSlots[2]->setDirMove(DIR_DOWN, petSlots[0]);
8944 			petSlots[2]->setDirMove(DIR_LEFT, petSlots[3]);
8945 
8946 			petSlots[3]->setDirMove(DIR_UP, petSlots[2]);
8947 			petSlots[3]->setDirMove(DIR_RIGHT, petSlots[1]);
8948 			petSlots[3]->setDirMove(DIR_DOWN, petSlots[0]);
8949 		}
8950 
8951 
8952 		for (int i = 0; i < petTips.size(); i++)
8953 		{
8954 			/*
8955 			if (hasPet && i == 0)
8956 			{
8957 				petTips[i]->alpha = 0;
8958 			}
8959 			else if (!hasPet && i == 1)
8960 				petTips[i]->alpha = 0;
8961 			else
8962 				petTips[i]->alpha = 1;
8963 			*/
8964 			petTips[i]->alpha = 1;
8965 		}
8966 
8967 		liCrystal->alpha = 1;
8968 
8969 
8970 		menu[7]->setFocus(true);
8971 
8972 
8973 		doMenuSectionHighlight(2);
8974 
8975 	}
8976 	else if (!f && petMenu)
8977 	{
8978 		for (int i = 0; i < petSlots.size(); i++)
8979 		{
8980 			petSlots[i]->alpha = 0;
8981 		}
8982 
8983 		for (int i = 0; i < petTips.size(); i++)
8984 		{
8985 			petTips[i]->alpha = 0;
8986 		}
8987 
8988 		liCrystal->alpha = 0;
8989 
8990 
8991 		menu[5]->setDirMove(DIR_LEFT, 0);
8992 		menu[5]->setDirMove(DIR_UP, 0);
8993 		menu[0]->setDirMove(DIR_UP, 0);
8994 	}
8995 
8996 	petMenu = f;
8997 }
8998 
toggleTreasureMenu(bool f)8999 void Game::toggleTreasureMenu(bool f)
9000 {
9001 	//debugLog("toggle treasure menu!");
9002 
9003 	if (optionsMenu)
9004 		toggleOptionsMenu(false);
9005 
9006 	if (foodMenu)
9007 		toggleFoodMenu(false);
9008 	if (petMenu)
9009 		togglePetMenu(false);
9010 
9011 	if (f && !treasureMenu)
9012 	{
9013 		currentMenuPage = MENUPAGE_TREASURES;
9014 
9015 		treasureMenu = true;
9016 		toggleMainMenu(false);
9017 
9018 		refreshTreasureSlots();
9019 
9020 		for (int i = 0; i < treasureTips.size(); i++)
9021 			treasureTips[i]->alpha = 1;
9022 
9023 		if (treasureSlots.size() > 8)
9024 		{
9025 			treasureSlots[0]->setDirMove(DIR_DOWN, menu[0]);
9026 			menu[0]->setDirMove(DIR_UP, treasureSlots[0]);
9027 
9028 			treasureSlots[2]->setDirMove(DIR_RIGHT, menu[5]);
9029 			menu[5]->setDirMove(DIR_LEFT, treasureSlots[2]);
9030 
9031 			treasureSlots[3]->setDirMove(DIR_RIGHT, menu[5]);
9032 		}
9033 
9034 		menu[8]->setFocus(true);
9035 
9036 		doMenuSectionHighlight(3);
9037 
9038 		liCrystal->alpha = 1;
9039 
9040 		circlePageNum->alpha = 1;
9041 	}
9042 	else if (!f && treasureMenu)
9043 	{
9044 		treasureMenu = false;
9045 
9046 		for (int i = 0; i < treasureTips.size(); i++)
9047 			treasureTips[i]->alpha = 0;
9048 
9049 		menu[0]->setDirMove(DIR_UP, 0);
9050 		menu[5]->setDirMove(DIR_LEFT, 0);
9051 
9052 		liCrystal->alpha = 0;
9053 
9054 		circlePageNum->alpha = 0;
9055 	}
9056 
9057 	for (int i = 0; i < treasureSlots.size(); i++)
9058 	{
9059 		if (f)
9060 			treasureSlots[i]->alpha = 1;
9061 		else
9062 			treasureSlots[i]->alpha = 0;
9063 	}
9064 
9065 	if (f)
9066 	{
9067 		nextTreasure->alpha = 1;
9068 		prevTreasure->alpha = 1;
9069 		use->alpha = 0;
9070 
9071 		treasureLabel->alpha = 0;
9072 		treasureDescription->alpha = 0;
9073 		treasureCloseUp->alpha = 0;
9074 	}
9075 	else
9076 	{
9077 		nextTreasure->alpha = 0;
9078 		prevTreasure->alpha = 0;
9079 		use->alpha = 0;
9080 
9081 		treasureLabel->alpha = 0;
9082 		treasureDescription->alpha = 0;
9083 		treasureCloseUp->alpha = 0;
9084 	}
9085 }
9086 
toggleRecipeList(bool on)9087 void Game::toggleRecipeList(bool on)
9088 {
9089 	recipeMenu.toggle(on, true);
9090 }
9091 
toggleFoodMenu(bool f)9092 void Game::toggleFoodMenu(bool f)
9093 {
9094 	if (optionsMenu)
9095 		toggleOptionsMenu(false);
9096 	if (petMenu)
9097 		togglePetMenu(false);
9098 	if (treasureMenu)
9099 		toggleTreasureMenu(false);
9100 
9101 
9102 	for (int i = 0; i < foodHolders.size(); i++)
9103 	{
9104 		if (f)
9105 			foodHolders[i]->alpha = 1;
9106 		else
9107 			foodHolders[i]->alpha = 0;
9108 	}
9109 
9110 	if (f)
9111 	{
9112 		if (dsq->game->avatar)
9113 		{
9114 			Path *p=0;
9115 			if (dsq->continuity.getFlag(FLAG_UPGRADE_WOK) > 0
9116 				|| ((p=dsq->game->getNearestPath(dsq->game->avatar->position, PATH_COOK))
9117 				&& p->isCoordinateInside(dsq->game->avatar->position)))
9118 			{
9119 				//cook->alpha = 1;
9120 				foodHolders[0]->alpha = 1;
9121 			}
9122 			else
9123 			{
9124 				foodHolders[0]->alpha = 0;
9125 			}
9126 		}
9127 	}
9128 
9129 	if (f && !foodMenu)
9130 	{
9131 		currentMenuPage = MENUPAGE_FOOD;
9132 
9133 		foodMenu = true;
9134 
9135 		toggleMainMenu(false);
9136 
9137 		refreshFoodSlots(false);
9138 
9139 		cook->alpha = 1;
9140 		recipes->alpha = 1;
9141 
9142 		prevFood->alpha = 1;
9143 		nextFood->alpha = 1;
9144 		foodLabel->alphaMod = 1;
9145 		foodDescription->alphaMod = 1;
9146 
9147 		foodSort->alpha = 1;
9148 
9149 		for (int i = 0; i < foodTips.size(); i++)
9150 			foodTips[i]->alpha = 1;
9151 
9152 		if (foodSlots.size() >= 16)
9153 		{
9154 			foodSlots[2]->setDirMove(DIR_RIGHT, menu[5]);
9155 			foodSlots[3]->setDirMove(DIR_RIGHT, menu[5]);
9156 			menu[5]->setDirMove(DIR_LEFT, foodSlots[2]);
9157 
9158 			treasureSlots[3]->setDirMove(DIR_RIGHT, menu[5]);
9159 
9160 			recipes->setDirMove(DIR_UP, foodSlots[15]);
9161 			foodSlots[15]->setDirMove(DIR_DOWN, recipes);
9162 			foodSlots[14]->setDirMove(DIR_DOWN, recipes);
9163 			foodSlots[0]->setDirMove(DIR_DOWN, recipes);
9164 
9165 			foodSlots[0]->setDirMove(DIR_LEFT, foodSlots[15]);
9166 			foodSlots[15]->setDirMove(DIR_RIGHT, foodSlots[0]);
9167 
9168 			foodSlots[15]->setDirMove(DIR_LEFT, foodSlots[14]);
9169 
9170 			recipes->setDirMove(DIR_RIGHT, menu[5]);
9171 		}
9172 
9173 		menu[6]->setFocus(true);
9174 
9175 		doMenuSectionHighlight(1);
9176 
9177 		liCrystal->alpha = 1;
9178 
9179 		circlePageNum->alpha = 1;
9180 
9181 		previewRecipe->alpha = 0;
9182 		updatePreviewRecipe();
9183 	}
9184 	else if (!f && foodMenu)
9185 	{
9186 		recipeMenu.toggle(false);
9187 		foodMenu = false;
9188 
9189 		cook->alpha = 0;
9190 		recipes->alpha = 0;
9191 		prevFood->alpha = 0;
9192 		nextFood->alpha = 0;
9193 		foodLabel->alphaMod = 0;
9194 		foodLabel->alpha = 0;
9195 		foodDescription->alpha = 0;
9196 		foodSort->alpha = 0;
9197 		showRecipe->alpha = 0;
9198 
9199 		liCrystal->alpha = 0;
9200 
9201 		for (int i = 0; i < foodTips.size(); i++)
9202 			foodTips[i]->alpha = 0;
9203 
9204 		menu[5]->setDirMove(DIR_LEFT, 0);
9205 
9206 		circlePageNum->alpha = 0;
9207 
9208 		previewRecipe->alpha = 0;
9209 	}
9210 
9211 	for (int i = 0; i < foodSlots.size(); i++)
9212 	{
9213 		foodSlots[i]->toggle(f);
9214 	}
9215 }
9216 
doMenuSectionHighlight(int section)9217 void Game::doMenuSectionHighlight(int section)
9218 {
9219 	for (int i = 0; i < 4; i++)
9220 		((AquariaMenuItem*)menu[(5+i)])->quad->alphaMod = 0.8;
9221 		//menu[(5+i)]->offset = Vector(0,-2);
9222 	((AquariaMenuItem*)menu[(5+section)])->quad->alphaMod = 1.0;
9223 	menuIconGlow->position = menu[5+section]->position;
9224 	/*
9225 	for (int i = 0; i < 4; i++)
9226 		menu[5+i]->color = Vector(0.5, 0.5, 0.5);
9227 
9228 	menu[5+section]->color = Vector(1,1,1);
9229 	*/
9230 }
9231 
toggleMainMenu(bool f)9232 void Game::toggleMainMenu(bool f)
9233 {
9234 	const float t = 0;
9235 	if (f)
9236 	{
9237 		currentMenuPage = MENUPAGE_SONGS;
9238 		for (int i = 0; i < songSlots.size(); i++)
9239 		{
9240 			//songSlots[i]->alpha.interpolateTo(1, t);
9241 			songSlots[i]->alphaMod = 1;
9242 		}
9243 		songBubbles->alpha.interpolateTo(1,t);
9244 		energyIdol->alpha.interpolateTo(1,t);
9245 		liCrystal->alpha.interpolateTo(1, t);
9246 		for (int i = 0; i < songTips.size(); i++)
9247 			songTips[i]->alpha = 1;
9248 		menuBg2->alpha.interpolateTo(1, t);
9249 
9250 
9251 		int sm=-900;
9252 		SongSlot *ss=0;
9253 		for (int i = 0; i < songSlots.size(); i++)
9254 		{
9255 			if (dsq->continuity.hasSong(dsq->continuity.getSongTypeBySlot(i)))
9256 			{
9257 				//if (songSlots[i]->alpha == 1 && songSlots[i]->renderQuad && songSlots[i]->alphaMod == 1)
9258 				{
9259 					Vector p = songSlots[i]->getWorldPosition();
9260 					if (p.x > sm)
9261 					{
9262 						sm = p.x;
9263 						ss = songSlots[i];
9264 					}
9265 				}
9266 			}
9267 		}
9268 
9269 		if (ss)
9270 		{
9271 			ss->setDirMove(DIR_RIGHT, (AquariaMenuItem*)menu[5]);
9272 		}
9273 		((AquariaMenuItem*)menu[5])->setDirMove(DIR_LEFT, ss);
9274 
9275 		doMenuSectionHighlight(0);
9276 	}
9277 	else
9278 	{
9279 		((AquariaMenuItem*)menu[5])->setDirMove(DIR_LEFT, 0);
9280 
9281 		for (int i = 0; i < songSlots.size(); i++)
9282 		{
9283 			songSlots[i]->alphaMod = 0;
9284 		}
9285 
9286 		for (int i = 0; i < songTips.size(); i++)
9287 			songTips[i]->alpha = 0;
9288 
9289 		songBubbles->alpha.interpolateTo(0, t);
9290 		energyIdol->alpha.interpolateTo(0,t);
9291 		liCrystal->alpha.interpolateTo(0, t);
9292 	}
9293 }
9294 
toggleKeyConfigMenu(bool f)9295 void Game::toggleKeyConfigMenu(bool f)
9296 {
9297 	const float t = 0;
9298 	playingSongInMenu = -1;
9299 
9300 
9301 	if (f && !keyConfigMenu)
9302 	{
9303 		//dsq->screenTransition->capture();
9304 
9305 		toggleOptionsMenu(false, false, true);
9306 
9307 		// Prevent int i from "leaking out" due to Microsoft extension to for-scope
9308 		{
9309 			for (int i = 0; i <= 1; i++)
9310 				menu[i]->alpha.interpolateTo(0, t);
9311 			for (int i = 4; i <= 8; i++)
9312 				menu[i]->alpha.interpolateTo(0, t);
9313 		}
9314 
9315 		toggleMainMenu(false);
9316 
9317 		menuBg2->alpha.interpolateTo(0, t);
9318 
9319 		keyConfigMenu = true;
9320 
9321 		group_keyConfig->setHidden(false);
9322 		group_keyConfig->alpha = 1;
9323 
9324 		dsq->user_bcontrol = dsq->user;
9325 
9326 		//group_keyConfig->children[group_keyConfig->children.size()-3]
9327 
9328 		RenderObject::Children::reverse_iterator i = group_keyConfig->children.rbegin();
9329 		AquariaKeyConfig *upright0 = (AquariaKeyConfig*)(*i);
9330 		i++;
9331 		AquariaKeyConfig *upright = (AquariaKeyConfig*)(*i);
9332 		i++; //i++;
9333 		AquariaKeyConfig *upleft = (AquariaKeyConfig*)(*i);
9334 
9335 		opt_cancel->setDirMove(DIR_UP, upright);
9336 		upright->setDirMove(DIR_DOWN, opt_cancel);
9337 		upright0->setDirMove(DIR_DOWN, opt_cancel);
9338 
9339 		opt_save->setDirMove(DIR_UP, upleft);
9340 		upleft->setDirMove(DIR_DOWN, opt_save);
9341 
9342 
9343 		opt_cancel->alpha = 1;
9344 		opt_save->alpha = 1;
9345 
9346 
9347 		opt_save->position = opt_save_original + Vector(0, 120);
9348 		opt_cancel->position = opt_cancel_original + Vector(0, 120);
9349 
9350 		opt_cancel->setFocus(true);
9351 
9352 		menuIconGlow->alpha = 0;
9353 
9354 		//dsq->screenTransition->transition(MENUPAGETRANSTIME);
9355 	}
9356 	else if (!f)
9357 	{
9358 		keyConfigMenu = false;
9359 
9360 		group_keyConfig->alpha = 0;
9361 		group_keyConfig->setHidden(true);
9362 
9363 		opt_cancel->alpha = 0;
9364 		opt_save->alpha = 0;
9365 
9366 		opt_save->position = opt_save_original;
9367 		opt_cancel->position = opt_cancel_original;
9368 
9369 		menuIconGlow->alpha = 1;
9370 	}
9371 }
9372 
toggleOptionsMenu(bool f,bool skipBackup,bool isKeyConfig)9373 void Game::toggleOptionsMenu(bool f, bool skipBackup, bool isKeyConfig)
9374 {
9375 	const float t = 0;
9376 	playingSongInMenu = -1;
9377 
9378 	if (f && !optionsMenu)
9379 	{
9380 		//menuBg->setTexture("gui/options-menu");
9381 		//menuBg->setWidthHeight(1024, 1024);
9382 
9383 		if (!isKeyConfig && !optionsOnly)
9384 		{
9385 			dsq->continuity.lastOptionsMenuPage = currentMenuPage;
9386 		}
9387 
9388 		toggleFoodMenu(false);
9389 		optionsMenu = true;
9390 		voxslider->setValue(dsq->user.audio.voxvol);
9391 		musslider->setValue(dsq->user.audio.musvol);
9392 		sfxslider->setValue(dsq->user.audio.sfxvol);
9393 
9394 		if (blurEffectsCheck)
9395 			blurEffectsCheck->setValue(dsq->user.video.blur);
9396 
9397 		flipInputButtonsCheck->setValue(dsq->user.control.flipInputButtons);
9398 		toolTipsCheck->setValue(dsq->user.control.toolTipsOn);
9399 		autoAimCheck->setValue(dsq->user.control.autoAim);
9400 		targetingCheck->setValue(dsq->user.control.targeting);
9401 
9402 		subtitlesCheck->setValue(dsq->user.audio.subtitles);
9403 		fullscreenCheck->setValue(dsq->isFullscreen());
9404 
9405 		if (ripplesCheck)
9406 			ripplesCheck->setValue(core->afterEffectManager!=0);
9407 
9408 		if (micInputCheck)
9409 			micInputCheck->setValue(dsq->user.audio.micOn);
9410 
9411 		if (resBox)
9412 		{
9413 			std::ostringstream os;
9414 			os << core->width << "x" << core->height;
9415 			if (!resBox->setSelectedItem(os.str()))
9416 			{
9417 				resBox->addItem(os.str());
9418 				resBox->setSelectedItem(os.str());
9419 			}
9420 		}
9421 
9422 		opt_cancel->setDirMove(DIR_UP, targetingCheck);
9423 		targetingCheck->setDirMove(DIR_DOWN, opt_cancel);
9424 
9425 
9426 		opt_save->setDirMove(DIR_UP, voxslider);
9427 		voxslider->setDirMove(DIR_DOWN, opt_save);
9428 
9429 		keyConfigButton->setDirMove(DIR_UP, targetingCheck);
9430 
9431 		if (!skipBackup)
9432 			dsq->user_backup = dsq->user;
9433 
9434 
9435 		options->alpha.interpolateTo(1, t);
9436 
9437 		for (int i = 0; i <= 1; i++)
9438 			menu[i]->alpha.interpolateTo(0, t);
9439 		for (int i = 4; i <= 9; i++)
9440 			menu[i]->alpha.interpolateTo(0, t);
9441 
9442 		toggleMainMenu(false);
9443 
9444 		keyConfigButton->alpha = 1;
9445 
9446 		menuBg2->alpha.interpolateTo(0, t);
9447 
9448 		opt_cancel->alpha = 1;
9449 		opt_save->alpha = 1;
9450 		opt_cancel->setFocus(true);
9451 
9452 		lips->alpha = 0;
9453 
9454 		liCrystal->alpha = 1;
9455 
9456 		optionsMenu = true;
9457 
9458 		menuIconGlow->alpha = 0;
9459 
9460 		/*
9461 		for (int i = 0; i < menu.size(); i++)
9462 			menu[i]->alpha.interpolateTo(0, 0.2);
9463 		*/
9464 	}
9465 	else if (!f && optionsMenu)
9466 	{
9467 		lips->alpha = 0;
9468 
9469 		keyConfigButton->alpha = 0;
9470 
9471 		options->alpha.interpolateTo(0, t);
9472 
9473 		opt_cancel->alpha = 0;
9474 		opt_save->alpha = 0;
9475 
9476 		liCrystal->alpha = 0;
9477 
9478 		/*
9479 		// what does this do?
9480 		if (optionsMenu)
9481 			((AquariaMenuItem*)menu[4])->setFocus(true);
9482 		*/
9483 			//((AquariaMenuItem*)menu[5])->setFocus(true);
9484 
9485 		optionsMenu = false;
9486 
9487 
9488 
9489 		if (!optionsOnly)
9490 		{
9491 			for (int i = 0; i <= 1; i++)
9492 				menu[i]->alpha.interpolateTo(1, t);
9493 			for (int i = 4; i <= 9; i++)
9494 			{
9495 				menu[i]->alpha.interpolateTo(1, t);
9496 			}
9497 
9498 			//menu[9]->alpha = 1;
9499 
9500 			if (!isKeyConfig)
9501 			{
9502 				switch(dsq->continuity.lastOptionsMenuPage)
9503 				{
9504 				case MENUPAGE_FOOD:
9505 					toggleFoodMenu(true);
9506 					((AquariaMenuItem*)menu[6])->setFocus(true);
9507 				break;
9508 				case MENUPAGE_TREASURES:
9509 					toggleTreasureMenu(true);
9510 					((AquariaMenuItem*)menu[8])->setFocus(true);
9511 				break;
9512 				case MENUPAGE_PETS:
9513 					togglePetMenu(true);
9514 					((AquariaMenuItem*)menu[7])->setFocus(true);
9515 				break;
9516 				case MENUPAGE_SONGS:
9517 				default:
9518 					toggleMainMenu(true);
9519 					((AquariaMenuItem*)menu[5])->setFocus(true);
9520 				break;
9521 				}
9522 			}
9523 
9524 			//((AquariaMenuItem*)menu[4])->setFocus(true);
9525 
9526 
9527 			menuBg2->alpha.interpolateTo(1, t);
9528 		}
9529 
9530 		menuIconGlow->alpha = 1;
9531 
9532 	}
9533 }
9534 
9535 float optsfxdly = 0;
updateOptionsMenu(float dt)9536 void Game::updateOptionsMenu(float dt)
9537 {
9538 	if (optionsMenu)
9539 	{
9540 		dsq->user.audio.voxvol				= voxslider->getValue();
9541 		dsq->user.audio.sfxvol				= sfxslider->getValue();
9542 		dsq->user.audio.musvol				= musslider->getValue();
9543 
9544 		if (micInputCheck)
9545 			dsq->user.audio.micOn			= micInputCheck->getValue();
9546 
9547 		dsq->user.control.flipInputButtons	= flipInputButtonsCheck->getValue();
9548 		dsq->user.control.toolTipsOn		= toolTipsCheck->getValue();
9549 		dsq->user.control.autoAim			= autoAimCheck->getValue();
9550 		dsq->user.control.targeting			= targetingCheck->getValue();
9551 
9552 		dsq->user.audio.subtitles			= subtitlesCheck->getValue();
9553 		dsq->user.video.full				= fullscreenCheck->getValue();
9554 
9555 		if (ripplesCheck)
9556 			dsq->user.video.fbuffer			= ripplesCheck->getValue();
9557 
9558 		if (blurEffectsCheck)
9559 			dsq->user.video.blur			= blurEffectsCheck->getValue();
9560 
9561 		if (resBox)
9562 		{
9563 			std::string s = resBox->getSelectedItemString();
9564 			if (!s.empty())
9565 			{
9566 				int pos = s.find('x');
9567 				std::istringstream is1(s.substr(0, pos));
9568 				is1 >> dsq->user.video.resx;
9569 				std::istringstream is2(s.substr(pos+1, s.size()-(pos+1)));
9570 				is2 >> dsq->user.video.resy;
9571 			}
9572 
9573 		}
9574 
9575 		/*
9576 		dsq->user.audio.sfxvol = sfxslider->getValue();
9577 		dsq->user.audio.musvol = musslider->getValue();
9578 		*/
9579 
9580 		optsfxdly += dt;
9581 		if (sfxslider->hadInput())
9582 		{
9583 			dsq->sound->playSfx("denied");
9584 		}
9585 		else if (voxslider->hadInput())
9586 		{
9587 			if (!dsq->sound->isPlayingVoice())
9588 				dsq->voice("naija_somethingfamiliar");
9589 		}
9590 		else if (optsfxdly > 0.6f)
9591 		{
9592 			optsfxdly = 0;
9593 			if (sfxslider->isGrabbed())
9594 			{
9595 				dsq->sound->playSfx("denied");
9596 				dsq->loops.updateVolume();
9597 				if (dsq->game->avatar)
9598 					dsq->game->avatar->updateHeartbeatSfx();
9599 			}
9600 			if (voxslider->isGrabbed())
9601 			{
9602 				if (!dsq->sound->isPlayingVoice())
9603 				{
9604 					dsq->voice("naija_somethingfamiliar");
9605 				}
9606 			}
9607 		}
9608 
9609 		/*
9610 		std::ostringstream os;
9611 		os << "musvol: " << dsq->user.audio.musvol;
9612 		debugLog(os.str());
9613 		*/
9614 
9615 		dsq->user.apply();
9616 	}
9617 }
9618 
updateInGameMenu(float dt)9619 void Game::updateInGameMenu(float dt)
9620 {
9621 	if (isInGameMenu())
9622 	{
9623 		menuOpenTimer += dt;
9624 		if (dt > 10)
9625 			dt = 10;
9626 
9627 		if (foodMenu)
9628 		{
9629 			if (dsq->inputMode == INPUT_JOYSTICK)
9630 			{
9631 				//debugLog("food menu, joystick");
9632 
9633 
9634 				/*
9635 				*/
9636 			}
9637 
9638 			if (dsq->continuity.hasIngredients())
9639 			{
9640 				int pageNum = (currentFoodPage+1);
9641 				int numPages = ((dsq->continuity.ingredientCount()-1)/foodPageSize)+1;
9642 
9643 				std::ostringstream os;
9644 				os << pageNum << "/" << numPages;
9645 				circlePageNum->setText(os.str());
9646 
9647 				if (pageNum > numPages && pageNum > 1)
9648 				{
9649 					onPrevFoodPage();
9650 				}
9651 			}
9652 			else
9653 			{
9654 				circlePageNum->setText("1/1");
9655 			}
9656 		}
9657 		if (treasureMenu)
9658 		{
9659 			std::ostringstream os;
9660 			os << (currentTreasurePage+1) << "/" << (numTreasures/treasurePageSize);
9661 			circlePageNum->setText(os.str());
9662 		}
9663 		// HACK: move this later
9664 		updateOptionsMenu(dt);
9665 		if (playingSongInMenu != -1)
9666 		{
9667 			songMenuPlayDelay += dt;
9668 
9669 			Song s = dsq->continuity.songBank[playingSongInMenu];
9670 
9671 			if (currentSongMenuNote < s.notes.size())
9672 			{
9673 				if (songMenuPlayDelay >= 0.5f)
9674 				{
9675 					songMenuPlayDelay = 0;
9676 
9677 
9678 					if (currentSongMenuNote >= 0 && currentSongMenuNote < s.notes.size())
9679 					{
9680 						/*
9681 						std::ostringstream os;
9682 						os << "MenuNote" << s[currentSongMenuNote];
9683 						*/
9684 						sound->playSfx(dsq->game->getNoteName(s.notes[currentSongMenuNote], "Menu"));
9685 
9686 						float a = (s.notes[currentSongMenuNote]*2*PI)/8.0f;
9687 						int sz = 110*menuBg->scale.x;
9688 						Vector notePos(sinf(a)*sz,cosf(a)*sz);
9689 
9690 						float t = 0.5;
9691 						Quad *q = new Quad("particles/glow", Vector(400+237*menuBg->scale.x,300-52*menuBg->scale.x)+notePos);
9692 						q->setBlendType(RenderObject::BLEND_ADD);
9693 						q->scale = Vector(5,5);
9694 						q->alpha.ensureData();
9695 						q->alpha.data->path.addPathNode(0, 0);
9696 						q->alpha.data->path.addPathNode(0.75, 0.5);
9697 						q->alpha.data->path.addPathNode(0.75, 0.5);
9698 						q->alpha.data->path.addPathNode(0, 1);
9699 						q->alpha.startPath(t);
9700 						q->followCamera = 1;
9701 						q->setLife(t);
9702 						q->setDecayRate(1);
9703 
9704 						game->addRenderObject(q, LR_HUD);
9705 
9706 						currentSongMenuNote++;
9707 					}
9708 					else
9709 					{
9710 
9711 						/*
9712 						if (playedDudNote)
9713 							playingSongInMenu = -1;
9714 						else
9715 							playedDudNote = true;
9716 						*/
9717 					}
9718 				}
9719 			}
9720 			else
9721 			{
9722 				if (songMenuPlayDelay >= 1.0f)
9723 				{
9724 					playingSongInMenu = -1;
9725 				}
9726 			}
9727 		}
9728 	}
9729 }
9730 
9731 
updateCursor(float dt)9732 void Game::updateCursor(float dt)
9733 {
9734 	bool rotate = false;
9735 
9736 	if (dsq->inputMode == INPUT_MOUSE)
9737 	{
9738 		dsq->cursor->offset.stop();
9739 		dsq->cursor->offset = Vector(0,0);
9740 		//debugLog("offset lerp stop in mouse!");
9741 	}
9742 	else if (dsq->inputMode == INPUT_JOYSTICK)
9743 	{
9744 		if (!dsq->game->isPaused() || dsq->game->isInGameMenu() || !dsq->game->avatar->isInputEnabled())
9745 		{
9746 			int offy = -60;
9747 			if (dsq->game->isInGameMenu() || !dsq->game->avatar->isInputEnabled())
9748 			{
9749 				//cursor->setTexture("");
9750 				offy = 0;
9751 			}
9752 			if (!dsq->cursor->offset.isInterpolating())
9753 			{
9754 				//debugLog("offset lerp!");
9755 				dsq->cursor->offset = Vector(0, offy);
9756 				dsq->cursor->offset.interpolateTo(Vector(0, offy-20), 0.4, -1, 1, 1);
9757 			}
9758 		}
9759 		else
9760 		{
9761 			//debugLog("offset lerp stop in joystick!");
9762 			dsq->cursor->offset.stop();
9763 			dsq->cursor->offset = Vector(0,0);
9764 		}
9765 	}
9766 
9767 	if (isSceneEditorActive() || dsq->game->isPaused() || (!avatar || !avatar->isInputEnabled()) ||
9768 		(dsq->game->miniMapRender && dsq->game->miniMapRender->isCursorIn())
9769 		)
9770 	{
9771 		dsq->setCursor(CURSOR_NORMAL);
9772 		// Don't show the cursor in keyboard/joystick mode if it's not
9773 		// already visible (this keeps the cursor from appearing for an
9774 		// instant during map fadeout).
9775 		if (dsq->inputMode == INPUT_MOUSE || isSceneEditorActive() || dsq->game->isPaused())
9776 			dsq->cursor->alphaMod = 0.5;
9777 
9778 		/*
9779 		dsq->cursor->offset.stop();
9780 		dsq->cursor->offset = Vector(0,0);
9781 		*/
9782 	}
9783 	else if (avatar)
9784 	{
9785 		//Vector v = avatar->getVectorToCursorFromScreenCentre();
9786 		if (dsq->inputMode == INPUT_JOYSTICK)// && !avatar->isSinging() && !dsq->game->isInGameMenu() && !dsq->game->isPaused())
9787 		{
9788 			dsq->cursor->alphaMod = 0;
9789 			if (!avatar->isSinging())
9790 				core->setMousePosition(core->center);
9791 			if (!dsq->game->isPaused())
9792 			{
9793 				/*
9794 
9795 				*/
9796 			}
9797 
9798 		}
9799 		else
9800 		{
9801 			dsq->cursor->offset.stop();
9802 			dsq->cursor->offset = Vector(0,0);
9803 
9804 			dsq->cursor->alphaMod = 0.5;
9805 		}
9806 		Vector v = avatar->getVectorToCursor();
9807 		if (avatar->looking)
9808 		{
9809 			dsq->setCursor(CURSOR_LOOK);
9810 		}
9811 		else if (avatar->isSinging())
9812 		{
9813 			dsq->setCursor(CURSOR_SING);
9814 		}
9815 		else if (dsq->game->isInGameMenu() || v.isLength2DIn(avatar->getStopDistance()) || (avatar->entityToActivate || avatar->pathToActivate))
9816 		{
9817 			dsq->setCursor(CURSOR_NORMAL);
9818 		}
9819 		else if (!v.isLength2DIn(avatar->getBurstDistance()) /*|| avatar->state.lockedToWall*/ /*|| avatar->bursting*/)
9820 		{
9821 			dsq->setCursor(CURSOR_BURST);
9822 			rotate = true;
9823 		}
9824 		else
9825 		{
9826 			dsq->setCursor(CURSOR_SWIM);
9827 			rotate = true;
9828 		}
9829 	}
9830 	if (rotate)
9831 	{
9832 		if (avatar)
9833 		{
9834 			Vector vec = dsq->getGameCursorPosition() - avatar->position;
9835 			float angle=0;
9836 			MathFunctions::calculateAngleBetweenVectorsInDegrees(Vector(0,0,0), vec, angle);
9837 			angle = 180-(360-angle);
9838 			angle += 90;
9839 			dsq->cursor->rotation.z = angle;
9840 		}
9841 	}
9842 	else
9843 	{
9844 		dsq->cursor->rotation.z = 0;
9845 	}
9846 }
9847 
constrainCamera()9848 void Game::constrainCamera()
9849 {
9850 	cameraOffBounds = 0;
9851 	if (cameraConstrained)
9852 	{
9853 		float vw2 = core->getVirtualOffX()*core->invGlobalScale;
9854 		float vh2 = core->getVirtualOffY()*core->invGlobalScale;
9855 
9856 		if (dsq->cameraPos.x - vw2 < (cameraMin.x+1))
9857 		{
9858 			dsq->cameraPos.x = (cameraMin.x+1) + vw2;
9859 			cameraOffBounds = 1;
9860 		}
9861 
9862 		if (dsq->cameraPos.y <= (cameraMin.y+1))
9863 		{
9864 			dsq->cameraPos.y = (cameraMin.y+1) + vh2;
9865 			cameraOffBounds = 1;
9866 		}
9867 
9868 		// The camera is positioned at (0, 0) screen coordinates, which, on widescreen resolutions,
9869 		// is *not* the upper left corner. Subtract the offset to get the real position.
9870 		// HACK: One column shows through after blackness ends, adding TILE_SIZE fixes this. -- fg
9871 		float scrw = (core->getVirtualWidth()-core->getVirtualOffX()+TILE_SIZE)*core->invGlobalScale;
9872 		float scrh = 600*core->invGlobalScale;
9873 
9874 		if (cameraMax.x != -1 && dsq->cameraPos.x + scrw >= cameraMax.x)
9875 		{
9876 			dsq->cameraPos.x = cameraMax.x - scrw;
9877 			cameraOffBounds = 1;
9878 		}
9879 
9880 		if (cameraMax.y != -1 && dsq->cameraPos.y + scrh >= cameraMax.y)
9881 		{
9882 			dsq->cameraPos.y = cameraMax.y - scrh;
9883 			cameraOffBounds = 1;
9884 		}
9885 	}
9886 }
9887 
areEntitiesUnique()9888 bool areEntitiesUnique()
9889 {
9890 	bool unique = true;
9891 	int c = 0;
9892 
9893 	FOR_ENTITIES(i)
9894 	{
9895 		Entity *e = *i;
9896 		FOR_ENTITIES(j)
9897 		{
9898 			Entity *e2 = *j;
9899 			if (e != e2)
9900 			{
9901 				if (e->getID() == e2->getID())
9902 				{
9903 					std::ostringstream os;
9904 					os << "found non-unique entity: " << e->getID() << " names, " << e->name << " and " << e2->name;
9905 					debugLog(os.str());
9906 					unique = false;
9907 					c++;
9908 				}
9909 			}
9910 		}
9911 	}
9912 	if (unique)
9913 	{
9914 		debugLog("Entity IDs are unique");
9915 	}
9916 	else
9917 	{
9918 		std::ostringstream os;
9919 		os << c << " Entity IDs are NOT unique";
9920 		debugLog(os.str());
9921 	}
9922 	return unique;
9923 }
9924 
isControlHint()9925 bool Game::isControlHint()
9926 {
9927 	return controlHint_bg->alpha.x != 0;
9928 }
9929 
trace(Vector start,Vector target)9930 bool Game::trace(Vector start, Vector target)
9931 {
9932 	/*
9933 	TileVector tstart(start);
9934 	TileVector ttarget(target);
9935 	*/
9936 	int i = 0;
9937 	Vector mov(target-start);
9938 	Vector pos = start;
9939 	//mov.normalize2D();
9940 	//mov |= g;
9941 	//mov |= 0.5;
9942 	mov.setLength2D(TILE_SIZE*1);
9943 	int c = 0;
9944 	// 1024
9945 	while (c < 2048*10)
9946 	{
9947 		pos += mov;
9948 
9949 
9950 		if (dsq->game->isObstructed(TileVector(pos)))
9951 			return false;
9952 
9953 
9954 		//Vector diff(tstart.x - ttarget.x, tstart.y - ttarget.y);
9955 		Vector diff = target - pos;
9956 		if (diff.getSquaredLength2D() <= sqr(TILE_SIZE*2))
9957 			//close enough!
9958 			return true;
9959 
9960 		Vector pl = mov.getPerpendicularLeft();
9961 		Vector pr = mov.getPerpendicularRight();
9962 		i = 1;
9963 		for (i = 1; i <= 6; i++)
9964 		{
9965 			TileVector tl(pos + pl*i);//(start.x + pl.x*i, start.y + pl.y*i);
9966 			TileVector tr(pos + pr*i);//(start.x + pr.x*i, start.y + pr.y*i);
9967 			if (dsq->game->isObstructed(tl) || dsq->game->isObstructed(tr))
9968 				return false;
9969 		}
9970 
9971 		c++;
9972 	}
9973 	return false;
9974 }
9975 
9976 const float bgLoopFadeTime = 1;
updateBgSfxLoop()9977 void Game::updateBgSfxLoop()
9978 {
9979 	if (!avatar) return;
9980 
9981 	Path *p = getNearestPath(dsq->game->avatar->position, PATH_BGSFXLOOP);
9982 	if (p && p->isCoordinateInside(dsq->game->avatar->position) && !p->content.empty())
9983 	{
9984 		if (bgSfxLoopPlaying2 != p->content)
9985 		{
9986 			if (dsq->loops.bg2 != BBGE_AUDIO_NOCHANNEL)
9987 			{
9988 				core->sound->fadeSfx(dsq->loops.bg2, SFT_OUT, bgLoopFadeTime);
9989 				dsq->loops.bg2 = BBGE_AUDIO_NOCHANNEL;
9990 				bgSfxLoopPlaying2 = "";
9991 			}
9992 			PlaySfx play;
9993 			play.name = p->content;
9994 			play.time = bgLoopFadeTime;
9995 			play.fade = SFT_IN;
9996 			play.vol = 1;
9997 			play.loops = -1;
9998 			play.priority = 0.7;
9999 			dsq->loops.bg2 = core->sound->playSfx(play);
10000 			bgSfxLoopPlaying2 = p->content;
10001 		}
10002 	}
10003 	else
10004 	{
10005 		if (dsq->loops.bg2 != BBGE_AUDIO_NOCHANNEL)
10006 		{
10007 			core->sound->fadeSfx(dsq->loops.bg2, SFT_OUT, bgLoopFadeTime);
10008 			dsq->loops.bg2 = BBGE_AUDIO_NOCHANNEL;
10009 			bgSfxLoopPlaying2 = "";
10010 		}
10011 	}
10012 
10013 	if (avatar->isUnderWater(avatar->getHeadPosition()))
10014 	{
10015 		dsq->game->switchBgLoop(0);
10016 	}
10017 	else
10018 		dsq->game->switchBgLoop(1);
10019 }
10020 
10021 const float helpTextScrollSpeed = 800.0f;
10022 const float helpTextScrollClickAmount = 340.0f;
10023 const float helpTextScrollClickTime = -helpTextScrollSpeed;
onHelpDown()10024 void Game::onHelpDown()
10025 {
10026 	float to = helpText->offset.y - helpTextScrollClickAmount;
10027 	if (to < -helpText->getHeight() + core->getVirtualHeight())
10028 	{
10029 		to = -helpText->getHeight() + core->getVirtualHeight();
10030 	}
10031 	helpText->offset.interpolateTo(Vector(0, to), helpTextScrollClickTime);
10032 }
10033 
onHelpUp()10034 void Game::onHelpUp()
10035 {
10036 	float to = helpText->offset.y + helpTextScrollClickAmount;
10037 	if (to > 0)
10038 	{
10039 		to = 0;
10040 	}
10041 	helpText->offset.interpolateTo(Vector(0, to), helpTextScrollClickTime);
10042 }
10043 
update(float dt)10044 void Game::update(float dt)
10045 {
10046 	particleManager->clearInfluences();
10047 
10048 	if (inHelpScreen)
10049 	{
10050 		const float helpTextScrollSpeed = 400.0f;
10051 		if (isActing(ACTION_SWIMDOWN))
10052 		{
10053 			helpText->offset.stop();
10054 			helpText->offset.y -= helpTextScrollSpeed * dt;
10055 			if (helpText->offset.y < -helpText->getHeight() + core->getVirtualHeight())
10056 			{
10057 				helpText->offset.y = -helpText->getHeight() + core->getVirtualHeight();
10058 			}
10059 		}
10060 		if (isActing(ACTION_SWIMUP))
10061 		{
10062 			helpText->offset.stop();
10063 			helpText->offset.y += helpTextScrollSpeed * dt;
10064 			if (helpText->offset.y > 0)
10065 			{
10066 				helpText->offset.y = 0;
10067 			}
10068 		}
10069 	}
10070 	if (enqueuedPreviewRecipe)
10071 	{
10072 		updatePreviewRecipe();
10073 		enqueuedPreviewRecipe = 0;
10074 	}
10075 
10076 	if (moveFoodSlotToFront)
10077 	{
10078 		moveFoodSlotToFront->moveToFront();
10079 		moveFoodSlotToFront = 0;
10080 	}
10081 
10082 	if (ingOffYTimer > 0)
10083 	{
10084 		ingOffYTimer -= dt;
10085 		if (ingOffYTimer < 0)
10086 		{
10087 			ingOffYTimer = 0;
10088 			ingOffY = 0;
10089 		}
10090 	}
10091 
10092 	if (cookDelay > 0)
10093 	{
10094 		cookDelay -= dt;
10095 		if (cookDelay < 0)
10096 			cookDelay = 0;
10097 	}
10098 
10099 	if (avatar)
10100 	{
10101 		/*tintColor.update(dt);
10102 		if (core->afterEffectManager)
10103 		{
10104 			if (tintColor.isInterpolating())
10105 				core->afterEffectManager->setActiveShader(AS_GLOW);
10106 			else
10107 				core->afterEffectManager->setActiveShader(AS_NONE);
10108 
10109 			core->afterEffectManager->glowShader.setValue(tintColor.x, tintColor.y, tintColor.z, 1);
10110 		}*/
10111 
10112 		if (avatar->isRolling())
10113 			particleManager->addInfluence(ParticleInfluence(avatar->position, 300, 800, true));
10114 		else if (avatar->isCharging())
10115 			particleManager->addInfluence(ParticleInfluence(avatar->position, 100, 600, true));
10116 		else if (avatar->bursting)
10117 			particleManager->addInfluence(ParticleInfluence(avatar->position, 400, 200, true));
10118 		else
10119 			particleManager->addInfluence(ParticleInfluence(avatar->position, avatar->vel.getLength2D(), 24, false));
10120 
10121 
10122 		particleManager->setSuckPosition(0, avatar->position);
10123 		particleManager->setSuckPosition(1, avatar->position + avatar->vel + avatar->vel2);
10124 
10125 		//avatar->vel.getLength2D()
10126 		/*
10127 		for (Shot::Shots::iterator i = Shot::shots.begin(); i != Shot::shots.end(); i++)
10128 		{
10129 			Emitter::addInfluence(ParticleInfluence((*i)->position, 400, 128, true));
10130 		}
10131 		*/
10132 		/*
10133 		FOR_ENTITIES (i)
10134 		{
10135 			Entity *e = *i;
10136 			if (e->getEntityType() != ET_AVATAR && e->collideRadius > 0)
10137 			{
10138 				Emitter::addInfluence(ParticleInfluence(e->position, 200, e->collideRadius, false));
10139 			}
10140 		}
10141 		*/
10142 	}
10143 	updateParticlePause();
10144 	//areEntitiesUnique();
10145 	if (controlHintTimer > 0)
10146 	{
10147 		controlHintTimer -= dt;
10148 		if (controlHintTimer < 0)
10149 		{
10150 			controlHint_ignoreClear = false;
10151 			clearControlHint();
10152 		}
10153 	}
10154 	dsq->continuity.update(dt);
10155 
10156 	StateObject::update(dt);
10157 
10158 
10159 	for (ElementUpdateList::iterator e = elementUpdateList.begin(); e != elementUpdateList.end(); e++)
10160 	{
10161 		(*e)->update(dt);
10162 	}
10163 
10164 
10165 	int i = 0;
10166 	for (i = 0; i < dsq->game->getNumPaths(); i++)
10167 	{
10168 		dsq->game->getPath(i)->update(dt);
10169 	}
10170 
10171 	FOR_ENTITIES(j)
10172 	{
10173 		(*j)->postUpdate(dt);
10174 	}
10175 
10176 	FlockEntity::updateFlockData();
10177 
10178 	updateCurrentVisuals(dt);
10179 	updateCursor(dt);
10180 
10181 	updateBgSfxLoop();
10182 	/*
10183 	for (int i = 0; i < 2; i++)
10184 		dsq->spawnBubble(Vector(rand()%800 + core->cameraPos.x, rand()%600 + core->cameraPos.y, -0.05f), Vector(0, 0,0));
10185 	*/
10186 
10187 	// spawn bubbles
10188 	/*
10189 	const float spawnTime = 0.008;
10190 	static float bubbleTimer = 0;
10191 	bubbleTimer += dt;
10192 	int sx1, sx2, sy1, sy2;
10193 	int extra = 300;
10194 	sx1 = core->screenCullX1 - extra;
10195 	sx2 = core->screenCullX2 + extra;
10196 	sy1 = core->screenCullY1 - extra;
10197 	sy2 = core->screenCullY2 + extra;
10198 
10199 	while (bubbleTimer >= spawnTime)
10200 	{
10201 		Vector p(sx1 + rand()%(sx2-sx1),sy1 + rand()%(sy2-sy1));
10202 		Quad *q = new Quad;
10203 		q->scale = Vector(0.25,0.25);
10204 		q->position = p;
10205 		q->setTexture("bubble");
10206 		q->setLife(2);
10207 		q->setDecayRate(1);
10208 		q->alpha = 0;
10209 		q->alpha.interpolateTo(0.4, 1, 1, 1, 1);
10210 		addRenderObject(q, LR_ELEMENTS3);
10211 		q->velocity = Vector(((rand()%200)-100)/100.0f, ((rand()%200)-100)/100.0f);
10212 		q->velocity *= 32;
10213 		bubbleTimer -= spawnTime;
10214 	}
10215 	*/
10216 
10217 	sceneColor.update(dt);
10218 	sceneColor2.update(dt);
10219 	sceneColor3.update(dt);
10220 	dsq->sceneColorOverlay->color = sceneColor * sceneColor2 * sceneColor3;
10221 	if (bg)
10222 	{
10223 		setParallaxTextureCoordinates(bg, 0.3);
10224 	}
10225 	if (bg2)
10226 	{
10227 		setParallaxTextureCoordinates(bg2, 0.1);
10228 	}
10229 	updateInGameMenu(dt);
10230 	if (avatar && grad && bg && bg2)
10231 	{
10232 		//float d = avatar->position.y / float(40000.0);
10233 
10234 		/*
10235 		Vector top1(0.6, 0.8, 0.65);
10236 		Vector top2(0.1, 0.2, 0.4);
10237 		Vector btm1(0.1, 0.2, 0.4);
10238 		Vector btm2(0, 0, 0.1);
10239 		*/
10240 		/*
10241 		Vector top1(0.5, 0.65, 7);
10242 		Vector top2(0.2, 0.25, 0.3);
10243 		Vector btm1(0.2, 0.25, 0.3);
10244 		Vector btm2(0, 0, 0.1);
10245 		*/
10246 
10247 		/*
10248 		// dynamic gradient
10249 		Vector top1(99/256.0f, 166/256.0f, 170/256.0f);
10250 		Vector top2(86/256.0f, 150/256.0f, 154/256.0f);
10251 		Vector btm1(86/256.0f, 150/256.0f, 154/256.0f);
10252 		Vector btm2(66/256.0f, 109/256.0f, 122/256.0f);
10253 		btm2 *= 0.75;
10254 
10255 
10256 		Vector newtop1(105/256.0f, 190/256.0f, 200/256.0f);
10257 
10258 		grad->makeVertical(newtop1, btm2);
10259 		*/
10260 
10261 
10262 
10263 		//grad->makeVertical(top1*(1.0-d) + top2*(d), btm1*(1.0-d) + btm2*(d));
10264 		/*
10265 		float range = 0.5f;
10266 		float left = 1.0f - range;
10267 		float v = ((range-(d*range)) + left);
10268 		bg->color = Vector(v,v,v);
10269 		bg2->color = Vector(v,v,v);
10270 		*/
10271 
10272 	}
10273 
10274 #ifdef AQUARIA_BUILD_SCENEEDITOR
10275 	{
10276 		sceneEditor.update(dt);
10277 	}
10278 #endif
10279 
10280 	dsq->emote.update(dt);
10281 
10282 	if (!isPaused())
10283 	{
10284 		timer += dt;
10285 		while (timer > 1.0f)
10286 			timer -= 1.0f;
10287 
10288 		halfTimer += dt*0.5f;
10289 		while (halfTimer > 1.0f)
10290 			halfTimer -= 1.0f;
10291 	}
10292 
10293 
10294 	if (avatar && (avatar->isEntityDead() || avatar->health <= 0) && core->getNestedMains()==1 && !isPaused())
10295 	{
10296 		dsq->stopVoice();
10297 		/*
10298 		if (runGameOverScript && dsq->runScript("scripts/maps/" + sceneName + ".lua", "gameOver"))
10299 		{
10300 			// no game over for you!
10301 		}
10302 		else
10303 		*/
10304 		if (deathTimer > 0)
10305 		{
10306 			deathTimer -= dt;
10307 			if (deathTimer <= 0)
10308 			{
10309 				// run game over script
10310 
10311 				//errorLog("here");
10312 				core->enqueueJumpState("GameOver");
10313 			}
10314 		}
10315 	}
10316 	if (avatar && avatar->isSinging() && avatar->songInterfaceTimer > 0.5f)
10317 	{
10318 		avatar->entityToActivate = 0;
10319 		avatar->pathToActivate = 0;
10320 	}
10321 
10322 	if (avatar && core->getNestedMains() == 1 && !isPaused() && !avatar->isSinging() && activation)
10323 		// && dsq->continuity.form == FORM_NORMAL
10324 	{
10325 		dsq->continuity.refreshAvatarData(avatar);
10326 
10327 		Vector bigGlow(3,3);
10328 		float bigGlowTime = 0.4;
10329 		bool hadThingToActivate = (avatar->entityToActivate!=0 || avatar->pathToActivate!=0);
10330 		avatar->entityToActivate = 0;
10331 
10332 		if (avatar->canActivateStuff())
10333 		{
10334 			FOR_ENTITIES(i)
10335 			{
10336 				Entity *e = *i;
10337 				float sqrLen = (dsq->getGameCursorPosition() - e->position).getSquaredLength2D();
10338 				if (sqrLen < sqr(e->activationRadius)
10339 					&& (avatar->position-e->position).getSquaredLength2D() < sqr(e->activationRange)
10340 					&& e->activationType == Entity::ACT_CLICK
10341 					&& !e->position.isInterpolating()
10342 					)
10343 				{
10344 					//if (trace(avatar->position, e->position))
10345 					{
10346 						avatar->entityToActivate = e;
10347 						dsq->cursorGlow->alpha.interpolateTo(1, 0.2);
10348 						dsq->cursorBlinker->alpha.interpolateTo(1.0,0.1);
10349 						if (!hadThingToActivate)
10350 						{
10351 							dsq->cursorGlow->scale = Vector(1,1);
10352 							dsq->cursorGlow->scale.interpolateTo(bigGlow,bigGlowTime,1, -1, 1);
10353 						}
10354 					}
10355 					break;
10356 				}
10357 			}
10358 		}
10359 
10360 		avatar->pathToActivate = 0;
10361 		//if (!avatar->entityToActivate && !avatar->state.lockedToWall)
10362 
10363 
10364 		// make sure you also disable entityToActivate
10365 		if (dsq->game && dsq->game->avatar->canActivateStuff())
10366 		{
10367 			Path* p = dsq->game->getScriptedPathAtCursor(true);
10368 			if (p && p->cursorActivation)
10369 			{
10370 				Vector diff = p->nodes[0].position - dsq->game->avatar->position;
10371 
10372 				if (p->isCoordinateInside(dsq->game->avatar->position) || diff.getSquaredLength2D() < sqr(p->activationRange))
10373 				{
10374 					//if (trace(avatar->position, p->nodes[0].position))
10375 					{
10376 						avatar->pathToActivate = p;
10377 						dsq->cursorGlow->alpha.interpolateTo(1,0.2);
10378 						dsq->cursorBlinker->alpha.interpolateTo(1,0.2);
10379 						if (!hadThingToActivate)
10380 						{
10381 							dsq->cursorGlow->scale = Vector(1,1);
10382 							dsq->cursorGlow->scale.interpolateTo(bigGlow,bigGlowTime,1, -1, 1);
10383 						}
10384 					}
10385 				}
10386 			}
10387 		}
10388 
10389 		/*
10390 		if (!hadThingToActivate && (avatar->entityToActivate || avatar->pathToActivate))
10391 		{
10392 			debugLog("Spawning cursor particles");
10393 			dsq->spawnParticleEffect("CursorBurst", dsq->getGameCursorPosition());
10394 		}
10395 		*/
10396 	}
10397 
10398 	if (!activation)
10399 	{
10400 		avatar->entityToActivate = 0;
10401 		avatar->pathToActivate = 0;
10402 	}
10403 
10404 	if (!avatar->entityToActivate && !avatar->pathToActivate)
10405 	{
10406 		dsq->cursorGlow->alpha.interpolateTo(0, 0.2);
10407 		dsq->cursorBlinker->alpha.interpolateTo(0, 0.1);
10408 	}
10409 
10410 	if (!isSceneEditorActive())
10411 	{
10412 		if (!isPaused())
10413 			waterLevel.update(dt);
10414 
10415 		if (cameraFollow)
10416 		{
10417 			Vector dest = *cameraFollow;
10418 
10419 			if (avatar)
10420 			{
10421 				if (avatar->looking && !dsq->game->isPaused()) {
10422 					Vector diff = avatar->getAim();//dsq->getGameCursorPosition() - avatar->position;
10423 					diff.capLength2D(maxLookDistance);
10424 					dest += diff;
10425 				}
10426 				else {
10427 					avatar->looking = 0;
10428 				}
10429 			}
10430 
10431 			if (cameraLerpDelay==0)
10432 			{
10433 				//cameraLerpDelay = 0.15;
10434 				cameraLerpDelay = vars->defaultCameraLerpDelay;
10435 			}
10436 			Vector oldCamPos = dsq->cameraPos;
10437 			cameraInterp.stop();
10438 			cameraInterp.interpolateTo(dest, cameraLerpDelay);
10439 			dsq->cameraPos = getCameraPositionFor(cameraInterp);
10440 			constrainCamera();
10441 
10442 			float dd = (dsq->cameraPos - oldCamPos).getLength2D();
10443 		}
10444 
10445 		cameraInterp.update(dt);
10446 	}
10447 
10448 }
10449 
setElementLayerVisible(int bgLayer,bool v)10450 void Game::setElementLayerVisible(int bgLayer, bool v)
10451 {
10452 	core->getRenderObjectLayer(LR_ELEMENTS1+bgLayer)->visible = v;
10453 }
10454 
isElementLayerVisible(int bgLayer)10455 bool Game::isElementLayerVisible(int bgLayer)
10456 {
10457 	return core->getRenderObjectLayer(LR_ELEMENTS1+bgLayer)->visible;
10458 }
10459 
10460 /*
10461 void Game::cameraPanToNode(Path *p, int speed)
10462 {
10463 
10464 	cameraFollow = &p->nodes[0].position;
10465 }
10466 
10467 void Game::cameraRestore()
10468 {
10469 	setCameraFollow(avatar);
10470 }
10471 */
10472 
fireShot(const std::string & bankShot,Entity * firer,Entity * target,const Vector & pos,const Vector & aim,bool playSfx)10473 Shot *Game::fireShot(const std::string &bankShot, Entity *firer, Entity *target, const Vector &pos, const Vector &aim, bool playSfx)
10474 {
10475 	Shot *s = 0;
10476 	if (firer)
10477 	{
10478 		s = new Shot;
10479 		s->firer = firer;
10480 
10481 		if (pos.isZero())
10482 			s->position = firer->position;
10483 		else
10484 			s->position = pos;
10485 
10486 		if (target)
10487 			s->setTarget(target);
10488 
10489 		Shot::loadBankShot(bankShot, s);
10490 
10491 		if (!aim.isZero())
10492 			s->setAimVector(aim);
10493 		else
10494 		{
10495 			if (target && firer)
10496 				s->setAimVector(target->position - firer->position);
10497 			else if (firer)
10498 				s->setAimVector(firer->getNormal());
10499 			else
10500 				s->setAimVector(Vector(0,1));
10501 		}
10502 
10503 		s->updatePosition();
10504 		s->fire(playSfx);
10505 
10506 
10507 		core->getTopStateData()->addRenderObject(s, LR_PROJECTILES);
10508 	}
10509 
10510 	return s;
10511 }
10512 
fireShot(Entity * firer,const std::string & particleEffect,Vector position,bool big,Vector dir,Entity * target,int homing,int velLenOverride,int targetPt)10513 Shot* Game::fireShot(Entity *firer, const std::string &particleEffect, Vector position, bool big, Vector dir, Entity *target, int homing, int velLenOverride, int targetPt)
10514 {
10515 	//sound->playSfx("BasicShot", 255, 0, rand()%100 + 1000);
10516 	/*
10517 	DamageType dt;
10518 	if (firer->getEntityType() == ET_ENEMY)
10519 		dt = DT_ENEMY_ENERGYBLAST;
10520 	else if (firer->getEntityType() == ET_AVATAR)
10521 		dt = DT_AVATAR_ENERGYBLAST;
10522 	else
10523 		debugLog("UNDEFINED DAMAGE TYPE!");
10524 	int velLen = 900;
10525 	if (big)
10526 		velLen += 200;
10527 	if (velLenOverride != 0)
10528 		velLen = velLenOverride;
10529 	Shot *shot;
10530 	if (big && target)
10531 		shot = new Shot(dt, firer, position, target, "energyBlast", homing, velLen, 8, 0.1, 4, 2);
10532 	else
10533 	{
10534 		if (homing > 0)
10535 			shot = new Shot(dt, firer, position, target, "energyBlast", homing, velLen, 5, 0.1, 4, 1);
10536 		else
10537 			shot = new Shot(dt, firer, position, 0, "energyBlast", 0, velLen, 5, 0.1, 4, 1);
10538 	}
10539 	shot->setParticleEffect(particleEffect);
10540 	if (big)
10541 		shot->scale = Vector(1.5, 1.5);
10542 	//shot->velocity = dsq->getGameCursorPosition() - position;
10543 	if (dir.x == 0 && dir.y == 0 && target)
10544 	{
10545 		shot->velocity = target->position - firer->position;
10546 	}
10547 	else
10548 	{
10549 		shot->velocity = dir;
10550 	}
10551 	if (velLen != 0 && !shot->velocity.isZero())
10552 		shot->velocity.setLength2D(velLen);
10553 
10554 	if (firer->getEntityType() == ET_AVATAR && homing && target)
10555 	{
10556 		//std::ostringstream os;
10557 		//os << "targetvel(" << target->vel.x << ", " << target->vel.y << ")";
10558 		//debugLog(os.str());
10559 		if (!target->vel.isZero() && !target->vel.isNan())
10560 			shot->velocity += target->vel;
10561 	}
10562 	shot->targetPt = targetPt;
10563 	//shot->velocity += firer->vel;
10564 
10565 	core->getTopStateData()->addRenderObject(shot, LR_PROJECTILES);
10566 	return shot;
10567 	*/
10568 	debugLog("Old version of Game::fireShot is obsolete");
10569 	return 0;
10570 }
10571 
warpCameraTo(RenderObject * r)10572 void Game::warpCameraTo(RenderObject *r)
10573 {
10574 	warpCameraTo(r->position);
10575 }
10576 
warpCameraTo(Vector position)10577 void Game::warpCameraTo(Vector position)
10578 {
10579 	cameraInterp.stop();
10580 	cameraInterp = position;
10581 	dsq->cameraPos = getCameraPositionFor(position);
10582 }
10583 
snapCam()10584 void Game::snapCam()
10585 {
10586 	if (cameraFollow)
10587 		warpCameraTo(*cameraFollow);
10588 }
10589 
getElementTemplateForLetter(int i)10590 ElementTemplate Game::getElementTemplateForLetter(int i)
10591 {
10592 	float cell = 64.0f/512.0f;
10593 	//for (int i = 0; i < 27; i++)
10594 	ElementTemplate t;
10595 	t.idx = 1024+i;
10596 	t.gfx = "Aquarian";
10597 	int x = i,y=0;
10598 	while (x >= 6)
10599 	{
10600 		x -= 6;
10601 		y++;
10602 	}
10603 
10604 	t.tu1 = x*cell;
10605 	t.tv1 = y*cell;
10606 	t.tu2 = t.tu1 + cell;
10607 	t.tv2 = t.tv1 + cell;
10608 
10609 	t.tv2 = 1 - t.tv2;
10610 	t.tv1 = 1 - t.tv1;
10611 	std::swap(t.tv1,t.tv2);
10612 
10613 	t.w = 512*cell;
10614 	t.h = 512*cell;
10615 	//elementTemplates.push_back(t);
10616 	return t;
10617 }
10618 
loadElementTemplates(std::string pack)10619 void Game::loadElementTemplates(std::string pack)
10620 {
10621 
10622     stringToLower(pack);
10623 	/*
10624 	std::string fn = ("data/"+pack+".xml");
10625 	if (!exists(fn))
10626 	{
10627 		loadElementTemplatesDAT(pack);
10628 		return;
10629 	}
10630 	loadElementTemplatesXML(pack);
10631 	*/
10632 
10633 	elementTemplates.clear();
10634 
10635 	// HACK: need to uncache things! causes memory leak currently
10636 	bool doPrecache=false;
10637 	std::string fn;
10638 
10639 	if (dsq->mod.isActive())
10640 		fn = dsq->mod.getPath() + "tilesets/" + pack + ".txt";
10641 	else
10642 		fn = "data/tilesets/" + pack + ".txt";
10643 
10644 
10645 	if (lastTileset == fn)
10646 	{
10647 		doPrecache=false;
10648 	}
10649 
10650 	lastTileset = fn;
10651 	if (!exists(fn))
10652 	{
10653 		errorLog ("Could not open element template pack [" + fn + "]");
10654 		return;
10655 	}
10656 
10657 	if (doPrecache)
10658 	{
10659 		tileCache.clean();
10660 	}
10661 
10662 	InStream in(fn.c_str());
10663 	std::string line;
10664 	while (std::getline(in, line))
10665 	{
10666 		int idx=-1, w=-1, h=-1;
10667 		std::string gfx;
10668 		std::istringstream is(line);
10669 		is >> idx >> gfx >> w >> h;
10670 		ElementTemplate t;
10671 		t.idx = idx;
10672 		t.gfx = gfx;
10673 		if (w==0) w=-1;
10674 		if (h==0) h=-1;
10675 		t.w = w;
10676 		t.h = h;
10677 		elementTemplates.push_back(t);
10678 		if (doPrecache)
10679 			tileCache.precacheTex(gfx);
10680 	}
10681 	in.close();
10682 
10683 	for (int i = 0; i < elementTemplates.size(); i++)
10684 	{
10685 		for (int j = i; j < elementTemplates.size(); j++)
10686 		{
10687 			if (elementTemplates[i].idx > elementTemplates[j].idx)
10688 			{
10689 				std::swap(elementTemplates[i], elementTemplates[j]);
10690 			}
10691 		}
10692 	}
10693 	for (int i = 0; i < 27; i++)
10694 	{
10695 		elementTemplates.push_back(getElementTemplateForLetter(i));
10696 	}
10697 }
10698 
clearGrid(int v)10699 void Game::clearGrid(int v)
10700 {
10701 	// ensure that grid is really a byte-array
10702 	compile_assert(sizeof(grid) == MAX_GRID * MAX_GRID);
10703 
10704 	memset(grid, v, sizeof(grid));
10705 }
10706 
resetFromTitle()10707 void Game::resetFromTitle()
10708 {
10709 	overrideMusic = "";
10710 }
10711 
setGrid(ElementTemplate * et,Vector position,float rot360)10712 void Game::setGrid(ElementTemplate *et, Vector position, float rot360)
10713 {
10714 	for (int i = 0; i < et->grid.size(); i++)
10715 	{
10716 		TileVector t(position);
10717 		/*
10718 		std::ostringstream os;
10719 		os << "opos(" << position.x << ", " << position.y << ") centre(" << t.x << ", " << t.y << ")";
10720 		debugLog(os.str());
10721 		*/
10722 		int x = et->grid[i].x;
10723 		int y = et->grid[i].y;
10724 		if (rot360 >= 0 && rot360 < 90)
10725 		{
10726 		}
10727 		else if (rot360 >= 90 && rot360 < 180)
10728 		{
10729 			int swap = y;
10730 			y = x;
10731 			x = swap;
10732 			x = -x;
10733 		}
10734 		else if (rot360 >= 180 && rot360 < 270)
10735 		{
10736 			x = -x;
10737 			y = -y;
10738 		}
10739 		else if (rot360 >= 270 && rot360 < 360)
10740 		{
10741 			int swap = y;
10742 			y = x;
10743 			x = swap;
10744 			y = -y;
10745 		}
10746 		TileVector s(t.x+x, t.y+y);
10747 		//Vector v = Vector(position.x+et->grid[i].x*TILE_SIZE, position.y+et->grid[i].y*TILE_SIZE);
10748 		setGrid(s, OT_INVISIBLE);
10749 	}
10750 }
10751 
removeState()10752 void Game::removeState()
10753 {
10754 	const float fadeTime = 0.25;
10755 
10756 	dsq->toggleVersionLabel(false);
10757 
10758 	dsq->subtitlePlayer.hide(fadeTime);
10759 
10760 	dropIngrNames.clear();
10761 
10762 	debugLog("Entering Game::removeState");
10763 	shuttingDownGameState = true;
10764 	debugLog("avatar->endOfGameState()");
10765 	if (avatar)
10766 	{
10767 		avatar->endOfGameState();
10768 	}
10769 
10770 #ifdef AQUARIA_BUILD_SCENEEDITOR
10771 	debugLog("toggle sceneEditor");
10772 	if (sceneEditor.isOn())
10773 		sceneEditor.toggle(false);
10774 #endif
10775 
10776 	debugLog("gameSpeed");
10777 	dsq->gameSpeed.interpolateTo(1, 0);
10778 
10779 	debugLog("bgSfxLoop");
10780 
10781 	dsq->loops.stopAll();
10782 
10783 	debugLog("toggleCursor");
10784 
10785 	dsq->toggleCursor(0, fadeTime);
10786 
10787 	if (!isInGameMenu())
10788 		avatar->disableInput();
10789 
10790 	debugLog("control hint");
10791 
10792 	controlHint_ignoreClear = false;
10793 	clearControlHint();
10794 	dsq->overlay->color = 0;
10795 
10796 	//dsq->overlay->alpha = 0;
10797 	dsq->overlay->alpha.interpolateTo(1, fadeTime);
10798 	dsq->main(fadeTime);
10799 
10800 	/*
10801 	// to block on voice overs
10802 	while (dsq->isStreamingVoice())
10803 	{
10804 		dsq->main(FRAME_TIME);
10805 	}
10806 	*/
10807 	// AFTER TRANSITION:
10808 
10809 	dsq->rumble(0,0,0);
10810 
10811 	dsq->sound->clearFadingSfx();
10812 
10813 
10814 	ingredients.clear();
10815 
10816 	core->particlesPaused = false;
10817 
10818 	elementUpdateList.clear();
10819 	elementInteractionList.clear();
10820 
10821 	dsq->setCursor(CURSOR_NORMAL);
10822 	dsq->darkLayer.toggle(0);
10823 	dsq->shakeCamera(0,0);
10824 	if (core->afterEffectManager)
10825 		core->afterEffectManager->clear();
10826 
10827 	dsq->getRenderObjectLayer(LR_BLACKGROUND)->update = true;
10828 
10829 	//core->sound->fadeOut(1);
10830 	if (saveFile)
10831 	{
10832 		delete saveFile;
10833 		saveFile = 0;
10834 	}
10835 	/*
10836 	if (core->getEnqueuedJumpState() != "Game")
10837 	{
10838 		this->overrideMusic = "";
10839 	}
10840 	*/
10841 	dsq->continuity.zoom = core->globalScale;
10842 
10843 	dsq->game->toggleOverrideZoom(false);
10844 	dsq->game->avatar->myZoom.stop();
10845 	dsq->globalScale.stop();
10846 
10847 	dsq->game->avatar->myZoom = Vector(1,1);
10848 	dsq->globalScale = Vector(1,1);
10849 	core->globalScaleChanged();
10850 
10851 	for (int i = 0; i < getNumPaths(); i++)
10852 	{
10853 		Path *p = getPath(i);
10854 		p->destroy();
10855 		delete p;
10856 	}
10857 	clearPaths();
10858 
10859 	StateObject::removeState();
10860 	dsq->clearElements();
10861 	dsq->clearEntities();
10862 	avatar = 0;
10863 	//items.clear();
10864 #ifdef AQUARIA_BUILD_SCENEEDITOR
10865 	sceneEditor.shutdown();
10866 #endif
10867 
10868 	cameraFollow = 0;
10869 	core->cameraPos = Vector(0,0);
10870 	sceneColor.stop();
10871 
10872 	controlHint_mouseLeft = controlHint_mouseRight = controlHint_mouseMiddle = controlHint_mouseBody = controlHint_bg = controlHint_image = 0;
10873 	controlHint_text = 0;
10874 
10875 	miniMapRender = 0;
10876 	gridRender = 0;
10877 	gridRender2 = 0;
10878 	gridRender3 = 0;
10879 	edgeRender = 0;
10880 	gridRenderEnt = 0;
10881 	gridRenderUser1 = 0;
10882 	gridRenderUser2 = 0;
10883 	worldMapRender = 0;
10884 	//core->sound->stopStreamingOgg();
10885 
10886 	// optimize:: clear layers
10887 	/*
10888 	int c = 0;
10889 	for (DSQ::RenderObjectLayers::iterator i = core->renderObjectLayers.begin(); i != core->renderObjectLayers.end(); i++)
10890 	{
10891 		DSQ::RenderObjects *r = &(*i);
10892 		//if (c <= LR_HUD)
10893 		if (c<=LR_PARTICLES)
10894 			r->clear();
10895 		c++;
10896 	}
10897 	*/
10898 
10899 	clearObsRows();
10900 
10901 
10902 	debugLog("killAllShots");
10903 	Shot::killAllShots();
10904 	Shot::clearShotGarbage(); // make sure there are no pointers left (would lead to a crash on shutdown otherwise)
10905 	debugLog("killAllBeams");
10906 	Beam::killAllBeams();
10907 	debugLog("killAllWebs");
10908 	Web::killAllWebs();
10909 	debugLog("killAllSpores");
10910 	Spore::killAllSpores();
10911 
10912 	debugLog("clear Local Sounds");
10913 	core->sound->clearLocalSounds();
10914 
10915 	active = false;
10916 
10917 
10918 	dsq->routeShoulder = true;
10919 
10920 
10921 
10922 	debugLog("Game::removeState Done");
10923 	//core->sound->stopAllSounds();
10924 }
10925 
isActive()10926 bool Game::isActive()
10927 {
10928 	return active;
10929 }
10930 
isBoxIn(Vector pos1,Vector sz1,Vector pos2,Vector sz2)10931 bool isBoxIn(Vector pos1, Vector sz1, Vector pos2, Vector sz2)
10932 {
10933 	if ((pos1.x - sz1.x > pos2.x-sz2.x) && (pos1.x - sz1.x < pos2.x+sz2.x))
10934 	{
10935 		if ((pos1.y - sz1.y > pos2.y-sz2.y) && (pos1.y - sz1.y < pos2.y+sz2.y))
10936 			return true;
10937 		else if ((pos1.y + sz1.y > pos2.y-sz2.y) && (pos1.y + sz1.y < pos2.y+sz2.y))
10938 			return true;
10939 	}
10940 	else if ((pos1.x + sz1.x > pos2.x-sz2.x) && (pos1.x + sz1.x < pos2.x+sz2.x))
10941 	{
10942 		if ((pos1.y - sz1.y > pos2.y-sz2.y) && (pos1.y - sz1.y < pos2.y+sz2.y))
10943 			return true;
10944 		else if ((pos1.y + sz1.y > pos2.y-sz2.y) && (pos1.y + sz1.y < pos2.y+sz2.y))
10945 			return true;
10946 	}
10947 	return false;
10948 }
10949 
getClosestPointOnTriangle(Vector a,Vector b,Vector c,Vector p)10950 Vector Game::getClosestPointOnTriangle(Vector a, Vector b, Vector c, Vector p)
10951 {
10952    Vector  Rab = getClosestPointOnLine(a, b, p);
10953    Vector  Rbc = getClosestPointOnLine(b, c, p);
10954    Vector  Rca = getClosestPointOnLine(c, a, p);
10955    int RabDist = Rab.getSquaredLength2D();
10956    int RbcDist = Rab.getSquaredLength2D();
10957    int RcaDist = Rca.getSquaredLength2D();
10958    if (RabDist < RbcDist && RabDist < RcaDist)
10959    {
10960 	   return Rab;
10961    }
10962    if (RbcDist < RabDist && RbcDist < RcaDist)
10963 	   return Rbc;
10964 	return Rca;
10965 }
10966 
getClosestPointOnLine(Vector a,Vector b,Vector p)10967 Vector Game::getClosestPointOnLine(Vector a, Vector b, Vector p)
10968 {
10969    // Determine t (the length of the vector from ‘a’ to ‘p’)
10970 	Vector c = p - a;
10971    Vector V = b-a;
10972    V.normalize2D();
10973    float d = (a-b).getLength2D();
10974    float t = V.dot(c);
10975 
10976    // Check to see if ‘t’ is beyond the extents of the line segment
10977 
10978    if (t < 0) return a;
10979    if (t > d) return b;
10980 
10981    // Return the point between ‘a’ and ‘b’
10982 
10983    //set length of V to t;
10984    V.setLength2D(t);
10985    return a + V;
10986 }
10987 
collideCircleWithGrid(const Vector & position,float r)10988 bool Game::collideCircleWithGrid(const Vector& position, float r)
10989 {
10990 	Vector tile = position;
10991 	TileVector t(tile);
10992 	tile.x = t.x;
10993 	tile.y = t.y;
10994 
10995 	float hsz = TILE_SIZE/2;
10996 	int xrange=1,yrange=1;
10997 	xrange = (r/TILE_SIZE)+1;
10998 	yrange = (r/TILE_SIZE)+1;
10999 
11000 	for (int x = tile.x-xrange; x <= tile.x+xrange; x++)
11001 	{
11002 		for (int y = tile.y-yrange; y <= tile.y+yrange; y++)
11003 		{
11004 			int v = this->getGrid(TileVector(x, y));
11005 			if (v != 0)
11006 			{
11007 				//if (tile.x == x && tile.y == y) return true;
11008 				TileVector t(x, y);
11009 				lastCollidePosition = t.worldVector();
11010 				//if (tile.x == x && tile.y == y) return true;
11011 				float rx = (x*TILE_SIZE)+TILE_SIZE/2;
11012 				float ry = (y*TILE_SIZE)+TILE_SIZE/2;
11013 
11014 				float rSqr;
11015 				lastCollideTileType = (ObsType)v;
11016 
11017 				rSqr = sqr(position.x - (rx+hsz)) + sqr(position.y - (ry+hsz));
11018 				if (rSqr < sqr(r))	return true;
11019 
11020 				rSqr = sqr(position.x - (rx-hsz)) + sqr(position.y - (ry+hsz));
11021 				if (rSqr < sqr(r))	return true;
11022 
11023 				rSqr = sqr(position.x - (rx-hsz)) + sqr(position.y - (ry-hsz));
11024 				if (rSqr < sqr(r))	return true;
11025 
11026 				rSqr = sqr(position.x - (rx+hsz)) + sqr(position.y - (ry-hsz));
11027 				if (rSqr < sqr(r))	return true;
11028 
11029 
11030 				if (position.x > rx-hsz && position.x < rx+hsz)
11031 				{
11032 					if (fabsf(ry - position.y) < r+hsz)
11033 					{
11034 						return true;
11035 					}
11036 				}
11037 
11038 
11039 				if (position.y > ry-hsz && position.y < ry+hsz)
11040 				{
11041 					if (fabsf(rx - position.x) < r+hsz)
11042 					{
11043 						return true;
11044 					}
11045 				}
11046 			}
11047 		}
11048 	}
11049 	lastCollideTileType = OT_EMPTY;
11050 	return false;
11051 }
11052 
learnedRecipe(Recipe * r,bool effects)11053 void Game::learnedRecipe(Recipe *r, bool effects)
11054 {
11055 	if (nocasecmp(dsq->getTopStateData()->name,"Game")==0 && !applyingState)
11056 	{
11057 		std::ostringstream os;
11058 		os << dsq->continuity.stringBank.get(23) << " "  << r->resultDisplayName << " " << dsq->continuity.stringBank.get(24);
11059 		IngredientData *data = dsq->continuity.getIngredientDataByName(r->result);
11060 		if (data)
11061 		{
11062 			if (effects)
11063 			{
11064 				dsq->game->setControlHint(os.str(), 0, 0, 0, 3, std::string("gfx/ingredients/") + data->gfx);
11065 			}
11066 		}
11067 
11068 		/*
11069 		errorLog(os.str());
11070 		*/
11071 	}
11072 }
11073 
setIgnoreAction(AquariaActions ac,bool ignore)11074 void Game::setIgnoreAction(AquariaActions ac, bool ignore)
11075 {
11076 	if (ignore)
11077 		ignoredActions.insert(ac);
11078 	else
11079 		ignoredActions.erase(ac);
11080 }
11081 
isIgnoreAction(AquariaActions ac) const11082 bool Game::isIgnoreAction(AquariaActions ac) const
11083 {
11084 	return ignoredActions.find(ac) != ignoredActions.end();
11085 }
11086