1 // ==============================================================
2 //	This file is part of Glest (www.glest.org)
3 //
4 //	Copyright (C) 2001-2008 Marti�o Figueroa
5 //
6 //	You can redistribute this code and/or modify it under
7 //	the terms of the GNU General Public License as published
8 //	by the Free Software Foundation; either version 2 of the
9 //	License, or (at your option) any later version
10 // ==============================================================
11 
12 #include "gui.h"
13 
14 #include <cassert>
15 #include <algorithm>
16 
17 #include "world.h"
18 #include "renderer.h"
19 #include "game.h"
20 #include "upgrade.h"
21 #include "unit.h"
22 #include "metrics.h"
23 #include "display.h"
24 #include "platform_util.h"
25 #include "sound_renderer.h"
26 #include "util.h"
27 #include "faction.h"
28 #include "leak_dumper.h"
29 
30 using namespace Shared::Graphics;
31 using namespace Shared::Util;
32 
33 namespace Glest{ namespace Game{
34 
35 // =====================================================
36 // 	class Mouse3d
37 // =====================================================
38 
39 const float Mouse3d::fadeSpeed= 1.f/50.f;
40 
Mouse3d()41 Mouse3d::Mouse3d(){
42 	enabled= false;
43 	rot= 0;
44 	fade= 0.f;
45 }
46 
enable()47 void Mouse3d::enable(){
48 	enabled= true;
49 	fade= 0.f;
50 }
51 
update()52 void Mouse3d::update(){
53 	if(enabled){
54 		rot= (rot + 3) % 360;
55 		fade+= fadeSpeed;
56 		if(fade>1.f) fade= 1.f;
57 	}
58 }
59 
60 // ===============================
61 // 	class SelectionQuad
62 // ===============================
63 
SelectionQuad()64 SelectionQuad::SelectionQuad(){
65 	enabled= false;
66 	posDown= Vec2i(0);
67 	posUp= Vec2i(0);
68 }
69 
setPosDown(const Vec2i & posDown)70 void SelectionQuad::setPosDown(const Vec2i &posDown){
71 	enabled= true;
72 	this->posDown= posDown;
73 	this->posUp= posDown;
74 }
75 
setPosUp(const Vec2i & posUp)76 void SelectionQuad::setPosUp(const Vec2i &posUp){
77 	this->posUp= posUp;
78 }
79 
disable()80 void SelectionQuad::disable(){
81 	enabled= false;
82 }
83 
84 // =====================================================
85 // 	class Gui
86 // =====================================================
87 
88 //constructor
Gui()89 Gui::Gui(){
90     posObjWorld= Vec2i(54, 14);
91     computeSelection= false;
92 	validPosObjWorld= false;
93     activeCommandType= NULL;
94     activeCommandClass= ccStop;
95 	selectingBuilding= false;
96 	selectingPos= false;
97 	selectingMeetingPoint= false;
98 	activePos= invalidPos;
99 }
100 
init(Game * game)101 void Gui::init(Game *game){
102 	this->commander= game->getCommander();
103 	this->gameCamera= game->getGameCamera();
104 	this->console= game->getConsole();
105 	this->world= game->getWorld();
106 	selection.init(this, world->getThisFactionIndex());
107 }
108 
end()109 void Gui::end(){
110 	selection.clear();
111 }
112 
113 // ==================== get ====================
114 
getBuilding() const115 const UnitType *Gui::getBuilding() const{
116     assert(selectingBuilding);
117     return choosenBuildingType;
118 }
119 
120 // ==================== is ====================
121 
isPlacingBuilding() const122 bool Gui::isPlacingBuilding() const{
123 	return isSelectingPos() && activeCommandType!=NULL && activeCommandType->getClass()==ccBuild;
124 }
125 
126 // ==================== set ====================
127 
invalidatePosObjWorld()128 void Gui::invalidatePosObjWorld(){
129     validPosObjWorld= false;
130 }
131 
setComputeSelectionFlag()132 void Gui::setComputeSelectionFlag(){
133 	computeSelection= true;
134 }
135 
136 
137 // ==================== reset state ====================
138 
resetState()139 void Gui::resetState(){
140     selectingBuilding= false;
141 	selectingPos= false;
142 	selectingMeetingPoint= false;
143     activePos= invalidPos;
144 	activeCommandClass= ccStop;
145 	activeCommandType= NULL;
146 }
147 
148 // ==================== events ====================
149 
update()150 void Gui::update(){
151     setComputeSelectionFlag();
152 	mouse3d.update();
153 }
154 
tick()155 void Gui::tick(){
156 	computeDisplay();
157 }
158 
159 //in display coords
mouseValid(int x,int y)160 bool Gui::mouseValid(int x, int y){
161 	return computePosDisplay(x, y) != invalidPos;
162 }
163 
mouseDownLeftDisplay(int x,int y)164 void Gui::mouseDownLeftDisplay(int x, int y){
165 	if(!selectingPos && !selectingMeetingPoint){
166 		int posDisplay= computePosDisplay(x, y);
167 		if(posDisplay!= invalidPos){
168 			if(selection.isComandable()){
169 				if(selectingBuilding){
170 					mouseDownDisplayUnitBuild(posDisplay);
171 				}
172 				else{
173 					mouseDownDisplayUnitSkills(posDisplay);
174 				}
175 			}
176 			else{
177 				resetState();
178 			}
179 		}
180 		computeDisplay();
181 	}
182 }
183 
mouseMoveDisplay(int x,int y)184 void Gui::mouseMoveDisplay(int x, int y){
185 	computeInfoString(computePosDisplay(x, y));
186 }
187 
mouseDownLeftGraphics(int x,int y)188 void Gui::mouseDownLeftGraphics(int x, int y){
189 	if(selectingPos){
190 		//give standard orders
191 		giveTwoClickOrders(x, y);
192 		resetState();
193 	}
194 	//set meeting point
195 	else if(selectingMeetingPoint){
196 		if(selection.isComandable()){
197 			Vec2i targetPos;
198 			if(Renderer::getInstance().computePosition(Vec2i(x, y), targetPos)){
199 				commander->trySetMeetingPoint(selection.getFrontUnit(), targetPos);
200 			}
201 		}
202 		resetState();
203 	}
204 	else{
205 		selectionQuad.setPosDown(Vec2i(x, y));
206 		computeSelected(false);
207 	}
208 	computeDisplay();
209 }
210 
mouseDownRightGraphics(int x,int y)211 void Gui::mouseDownRightGraphics(int x, int y){
212 
213 	if(selectingPos || selectingMeetingPoint){
214 		resetState();
215 	}
216 	else if(selection.isComandable()){
217 		giveDefaultOrders(x, y);
218 	}
219 	computeDisplay();
220 }
221 
mouseUpLeftGraphics(int x,int y)222 void Gui::mouseUpLeftGraphics(int x, int y){
223 	if(!selectingPos && !selectingMeetingPoint){
224 		if(selectionQuad.isEnabled()){
225 			selectionQuad.setPosUp(Vec2i(x, y));
226 			if(selection.isComandable() && random.randRange(0, 1)==0){
227 				SoundRenderer::getInstance().playFx(
228 					selection.getFrontUnit()->getType()->getSelectionSound(),
229 					selection.getFrontUnit()->getCurrVector(),
230 					gameCamera->getPos());
231 			}
232 			selectionQuad.disable();
233 		}
234 	}
235 }
236 
mouseMoveGraphics(int x,int y)237 void Gui::mouseMoveGraphics(int x, int y){
238 
239 	//compute selection
240 	if(selectionQuad.isEnabled()){
241 		selectionQuad.setPosUp(Vec2i(x, y));
242 		if(computeSelection){
243 			computeSelection= false;
244 			computeSelected(false);
245 		}
246 	}
247 
248 	//compute position for building
249 	if(isPlacingBuilding()){
250 		validPosObjWorld= Renderer::getInstance().computePosition(Vec2i(x,y), posObjWorld);
251 	}
252 
253 	display.setInfoText("");
254 }
255 
mouseDoubleClickLeftGraphics(int x,int y)256 void Gui::mouseDoubleClickLeftGraphics(int x, int y){
257 	if(!selectingPos && !selectingMeetingPoint){
258 		selectionQuad.setPosDown(Vec2i(x, y));
259 		computeSelected(true);
260 		computeDisplay();
261 	}
262 }
263 
groupKey(int groupIndex)264 void Gui::groupKey(int groupIndex){
265 	if(isKeyDown(vkControl)){
266 		selection.assignGroup(groupIndex);
267 	}
268 	else{
269 		selection.recallGroup(groupIndex);
270 	}
271 }
272 
hotKey(char key)273 void Gui::hotKey(char key){
274 	if(key==' '){
275 		centerCameraOnSelection();
276 	}
277 	else if(key=='I'){
278 		selectInterestingUnit(iutIdleHarvester);
279 	}
280 	else if(key=='B'){
281 		selectInterestingUnit(iutBuiltBuilding);
282 	}
283 	else if(key=='R'){
284 		selectInterestingUnit(iutProducer);
285 	}
286 	else if(key=='D'){
287 		selectInterestingUnit(iutDamaged);
288 	}
289 	else if(key=='T'){
290 		selectInterestingUnit(iutStore);
291 	}
292 	else if(key=='A'){
293 		clickCommonCommand(ccAttack);
294 	}
295 	else if(key=='S'){
296 		clickCommonCommand(ccStop);
297 	}
298 	else if(key=='M'){
299 		clickCommonCommand(ccMove);
300 	}
301 }
302 
onSelectionChanged()303 void Gui::onSelectionChanged(){
304 	resetState();
305 	computeDisplay();
306 }
307 
308 // ================= PRIVATE =================
309 
giveOneClickOrders()310 void Gui::giveOneClickOrders(){
311 	CommandResult result;
312 	if(selection.isUniform()){
313 		result= commander->tryGiveCommand(&selection, activeCommandType);
314 	}
315 	else{
316 		result= commander->tryGiveCommand(&selection, activeCommandClass);
317 	}
318 	addOrdersResultToConsole(activeCommandClass, result);
319     activeCommandType= NULL;
320     activeCommandClass= ccStop;
321 }
322 
giveDefaultOrders(int x,int y)323 void Gui::giveDefaultOrders(int x, int y){
324 
325 	//compute target
326 	const Unit *targetUnit= NULL;
327 	Vec2i targetPos;
328 	if(!computeTarget(Vec2i(x, y), targetPos, targetUnit)){
329 		console->addStdMessage("InvalidPosition");
330 		return;
331 	}
332 
333 	//give order
334 	CommandResult result= commander->tryGiveCommand(&selection, targetPos, targetUnit);
335 
336 	//graphical result
337 	addOrdersResultToConsole(activeCommandClass, result);
338 	if(result == crSuccess || result == crSomeFailed){
339 		mouse3d.enable();
340 
341 		if(random.randRange(0, 1)==0){
342 			SoundRenderer::getInstance().playFx(
343 				selection.getFrontUnit()->getType()->getCommandSound(),
344 				selection.getFrontUnit()->getCurrVector(),
345 				gameCamera->getPos());
346 		}
347 	}
348 
349 	//reset
350 	resetState();
351 }
352 
giveTwoClickOrders(int x,int y)353 void Gui::giveTwoClickOrders(int x, int y){
354 
355 	CommandResult result;
356 
357 	//compute target
358 	const Unit *targetUnit= NULL;
359 	Vec2i targetPos;
360 	if(!computeTarget(Vec2i(x, y), targetPos, targetUnit)){
361 		console->addStdMessage("InvalidPosition");
362 		return;
363 	}
364 
365     //give orders to the units of this faction
366 	if(!selectingBuilding){
367 		if(selection.isUniform()){
368 			result= commander->tryGiveCommand(&selection, activeCommandType, targetPos, targetUnit);
369 		}
370 		else{
371 			result= commander->tryGiveCommand(&selection, activeCommandClass, targetPos, targetUnit);
372         }
373 	}
374 	else{
375 		//selecting building
376 		result= commander->tryGiveCommand( selection.getFrontUnit(), activeCommandType, posObjWorld, choosenBuildingType );
377     }
378 
379 	//graphical result
380 	addOrdersResultToConsole(activeCommandClass, result);
381 	if(result == crSuccess || result == crSomeFailed){
382 		mouse3d.enable();
383 
384 		if(random.randRange(0, 1)==0){
385 			SoundRenderer::getInstance().playFx(
386 				selection.getFrontUnit()->getType()->getCommandSound(),
387 				selection.getFrontUnit()->getCurrVector(),
388 				gameCamera->getPos());
389 		}
390 	}
391 }
392 
centerCameraOnSelection()393 void Gui::centerCameraOnSelection(){
394 	if(!selection.isEmpty()){
395 		Vec3f refPos= selection.getRefPos();
396 		gameCamera->centerXZ(refPos.x, refPos.z);
397 	}
398 }
399 
selectInterestingUnit(InterestingUnitType iut)400 void Gui::selectInterestingUnit(InterestingUnitType iut){
401 	const Faction* thisFaction= world->getThisFaction();
402 	const Unit* previousUnit= NULL;
403 	bool previousFound= true;
404 
405 	//start at the next harvester
406 	if(selection.getCount()==1){
407 		const Unit* refUnit= selection.getFrontUnit();
408 
409 		if(refUnit->isInteresting(iut)){
410 			previousUnit= refUnit;
411 			previousFound= false;
412 		}
413 	}
414 
415 	//clear selection
416 	selection.clear();
417 
418 	//search
419 	for(int i= 0; i<thisFaction->getUnitCount(); ++i){
420 		Unit* unit= thisFaction->getUnit(i);
421 
422 		if(previousFound){
423 			if(unit->isInteresting(iut)){
424 				selection.select(unit);
425 				break;
426 			}
427 		}
428 		else{
429 			if(unit==previousUnit){
430 				previousFound= true;
431 			}
432 		}
433 	}
434 
435 	//search again if we have a previous
436 	if(selection.isEmpty() && previousUnit!=NULL && previousFound==true){
437 		for(int i= 0; i<thisFaction->getUnitCount(); ++i){
438 			Unit* unit= thisFaction->getUnit(i);
439 
440 			if(unit->isInteresting(iut)){
441 				selection.select(unit);
442 				break;
443 			}
444 		}
445 	}
446 }
447 
clickCommonCommand(CommandClass commandClass)448 void Gui::clickCommonCommand(CommandClass commandClass){
449 	for(int i= 0; i<Display::downCellCount; ++i){
450 		const CommandType* ct= display.getCommandType(i);
451 		if((ct!=NULL && ct->getClass()==commandClass) || display.getCommandClass(i)==commandClass){
452 			mouseDownDisplayUnitSkills(i);
453 			break;
454 		}
455 	}
456 }
457 
mouseDownDisplayUnitSkills(int posDisplay)458 void Gui::mouseDownDisplayUnitSkills(int posDisplay){
459 	if(!selection.isEmpty()){
460 		if(posDisplay != cancelPos){
461 			if(posDisplay!=meetingPointPos){
462 				const Unit *unit= selection.getFrontUnit();
463 
464 				//uniform selection
465 				if(selection.isUniform()){
466 					if(unit->getFaction()->reqsOk(display.getCommandType(posDisplay))){
467 						activeCommandType= display.getCommandType(posDisplay);
468 						activeCommandClass= activeCommandType->getClass();
469 					}
470 					else{
471 						posDisplay= invalidPos;
472 						activeCommandType= NULL;
473 						activeCommandClass= ccStop;
474 						return;
475 					}
476 				}
477 
478 				//non uniform selection
479 				else{
480 					activeCommandType= NULL;
481 					activeCommandClass= display.getCommandClass(posDisplay);
482 				}
483 
484 				//give orders depending on command type
485 				if(!selection.isEmpty()){
486 					const CommandType *ct= selection.getUnit(0)->getType()->getFirstCtOfClass(activeCommandClass);
487 					if(activeCommandType!=NULL && activeCommandType->getClass()==ccBuild){
488 						assert(selection.isUniform());
489 						selectingBuilding= true;
490 					}
491 					else if(ct->getClicks()==cOne){
492 						invalidatePosObjWorld();
493 						giveOneClickOrders();
494 					}
495 					else{
496 						selectingPos= true;
497 						activePos= posDisplay;
498 					}
499 				}
500 			}
501 			else{
502 				activePos= posDisplay;
503 				selectingMeetingPoint= true;
504 			}
505 		}
506 		else{
507 			commander->tryCancelCommand(&selection);
508 		}
509 	}
510 }
511 
mouseDownDisplayUnitBuild(int posDisplay)512 void Gui::mouseDownDisplayUnitBuild(int posDisplay){
513 	int factionIndex= world->getThisFactionIndex();
514 
515 	if(posDisplay==cancelPos){
516 		resetState();
517 	}
518 	else{
519 		if(activeCommandType!=NULL && activeCommandType->getClass()==ccBuild){
520 			const BuildCommandType *bct= static_cast<const BuildCommandType*>(activeCommandType);
521 			const UnitType *ut= bct->getBuilding(posDisplay);
522 			if(world->getFaction(factionIndex)->reqsOk(ut)){
523 				choosenBuildingType= ut;
524 				assert(choosenBuildingType!=NULL);
525 				selectingPos= true;;
526 				activePos= posDisplay;
527 			}
528 		}
529 	}
530 }
531 
computeInfoString(int posDisplay)532 void Gui::computeInfoString(int posDisplay){
533 
534 	Lang &lang= Lang::getInstance();
535 
536 	display.setInfoText("");
537 	if(posDisplay!=invalidPos && selection.isComandable()){
538 		if(!selectingBuilding){
539 			if(posDisplay==cancelPos){
540 				display.setInfoText(lang.get("Cancel"));
541 			}
542 			else if(posDisplay==meetingPointPos){
543 				display.setInfoText(lang.get("MeetingPoint"));
544 			}
545 			else{
546 				//uniform selection
547 				if(selection.isUniform()){
548 					const Unit *unit= selection.getFrontUnit();
549 					const CommandType *ct= display.getCommandType(posDisplay);
550 					if(ct!=NULL){
551 						if(unit->getFaction()->reqsOk(ct)){
552 							display.setInfoText(ct->getDesc(unit->getTotalUpgrade()));
553 						}
554 						else{
555 							if(ct->getClass()==ccUpgrade){
556 								const UpgradeCommandType *uct= static_cast<const UpgradeCommandType*>(ct);
557 								if(unit->getFaction()->getUpgradeManager()->isUpgrading(uct->getProducedUpgrade())){
558 									display.setInfoText(lang.get("Upgrading"));
559 								}
560 								else if(unit->getFaction()->getUpgradeManager()->isUpgraded(uct->getProducedUpgrade())){
561 									display.setInfoText(lang.get("AlreadyUpgraded"));
562 								}
563 								else{
564 									display.setInfoText(ct->getReqDesc());
565 								}
566 							}
567 							else{
568 								display.setInfoText(ct->getReqDesc());
569 							}
570 						}
571 					}
572 				}
573 
574 				//non uniform selection
575 				else{
576 					const UnitType *ut= selection.getFrontUnit()->getType();
577 					CommandClass cc= display.getCommandClass(posDisplay);
578 					if(cc!=ccNull){
579 						display.setInfoText(lang.get("CommonCommand") + ": " + ut->getFirstCtOfClass(cc)->toString());
580 					}
581 				}
582 			}
583 		}
584 		else{
585 			if(posDisplay==cancelPos){
586 				display.setInfoText(lang.get("Return"));
587 			}
588 			else{
589 				if(activeCommandType!=NULL && activeCommandType->getClass()==ccBuild){
590 					const BuildCommandType *bct= static_cast<const BuildCommandType*>(activeCommandType);
591 					display.setInfoText(bct->getBuilding(posDisplay)->getReqDesc());
592 				}
593 			}
594 		}
595 	}
596 }
597 
computeDisplay()598 void Gui::computeDisplay(){
599 
600 	//init
601 	display.clear();
602 
603     // ================ PART 1 ================
604 
605 	//title, text and progress bar
606     if(selection.getCount()==1){
607 		display.setTitle(selection.getFrontUnit()->getFullName());
608 		display.setText(selection.getFrontUnit()->getDesc());
609 		display.setProgressBar(selection.getFrontUnit()->getProductionPercent());
610     }
611 
612     //portraits
613 	for(int i=0; i<selection.getCount(); ++i){
614 		display.setUpImage(i, selection.getUnit(i)->getType()->getImage());
615 	}
616 
617     // ================ PART 2 ================
618 
619 	if(selectingPos || selectingMeetingPoint){
620 		display.setDownSelectedPos(activePos);
621 	}
622 
623 	if(selection.isComandable()){
624 		if(!selectingBuilding){
625 
626 			//cancel button
627 			const Unit *u= selection.getFrontUnit();
628 			const UnitType *ut= u->getType();
629 			if(selection.isCancelable()){
630 				display.setDownImage(cancelPos, ut->getCancelImage());
631 				display.setDownLighted(cancelPos, true);
632 			}
633 
634 			//meeting point
635 			if(selection.isMeetable()){
636 				display.setDownImage(meetingPointPos, ut->getMeetingPointImage());
637 				display.setDownLighted(meetingPointPos, true);
638 			}
639 
640 			if(selection.isUniform()){
641 				//uniform selection
642 				if(u->isBuilt()){
643 					int morphPos= 8;
644 					for(int i=0; i<ut->getCommandTypeCount(); ++i){
645 						int displayPos= i;
646 						const CommandType *ct= ut->getCommandType(i);
647 						if(ct->getClass()==ccMorph){
648 							displayPos= morphPos++;
649 						}
650 						display.setDownImage(displayPos, ct->getImage());
651 						display.setCommandType(displayPos, ct);
652 						display.setDownLighted(displayPos, u->getFaction()->reqsOk(ct));
653 					}
654 				}
655 			}
656 
657 			else{
658 				//non uniform selection
659 				int lastCommand= 0;
660 				for(int i=0; i<ccCount; ++i){
661 					CommandClass cc= static_cast<CommandClass>(i);
662 					if(isSharedCommandClass(cc) && cc!=ccBuild){
663 						display.setDownLighted(lastCommand, true);
664 						display.setDownImage(lastCommand, ut->getFirstCtOfClass(cc)->getImage());
665 						display.setCommandClass(lastCommand, cc);
666 						lastCommand++;
667 					}
668 				}
669 			}
670 		}
671 		else{
672 
673 			//selecting building
674 			const Unit *unit= selection.getFrontUnit();
675 			if(activeCommandType!=NULL && activeCommandType->getClass()==ccBuild){
676 				const BuildCommandType* bct= static_cast<const BuildCommandType*>(activeCommandType);
677 				for(int i=0; i<bct->getBuildingCount(); ++i){
678 					display.setDownImage(i, bct->getBuilding(i)->getImage());
679 					display.setDownLighted(i, unit->getFaction()->reqsOk(bct->getBuilding(i)));
680 				}
681 				display.setDownImage(cancelPos, selection.getFrontUnit()->getType()->getCancelImage());
682 				display.setDownLighted(cancelPos, true);
683 			}
684 		}
685     }
686 }
687 
computePosDisplay(int x,int y)688 int Gui::computePosDisplay(int x, int y){
689 	int posDisplay= display.computeDownIndex(x, y);
690 
691 	if(posDisplay<0 || posDisplay>=Display::downCellCount){
692 		posDisplay= invalidPos;
693 	}
694 	else if(selection.isComandable()){
695 		if(posDisplay!=cancelPos){
696 			if(posDisplay!=meetingPointPos){
697 				if(!selectingBuilding){
698 					//standard selection
699 					if(display.getCommandClass(posDisplay)==ccNull && display.getCommandType(posDisplay)==NULL){
700 						posDisplay= invalidPos;
701 					}
702 				}
703 				else{
704 					//building selection
705 					if(activeCommandType!=NULL && activeCommandType->getClass()==ccBuild){
706 						const BuildCommandType *bct= static_cast<const BuildCommandType*>(activeCommandType);
707 						if(posDisplay>=bct->getBuildingCount()){
708 							posDisplay= invalidPos;
709 						}
710 					}
711 				}
712 			}
713 			else{
714 				//check meeting point
715 				if(!selection.isMeetable()){
716 					posDisplay= invalidPos;
717 				}
718 			}
719 		}
720 		else{
721 			//check cancel button
722 			if(!selection.isCancelable()){
723 				posDisplay= invalidPos;
724 			}
725 		}
726 	}
727 	else{
728         posDisplay= invalidPos;
729     }
730 
731 	return posDisplay;
732 }
733 
addOrdersResultToConsole(CommandClass cc,CommandResult result)734 void Gui::addOrdersResultToConsole(CommandClass cc, CommandResult result){
735 
736     switch(result){
737 	case crSuccess:
738 		break;
739 	case crFailReqs:
740         switch(cc){
741         case ccBuild:
742             console->addStdMessage("BuildingNoReqs");
743 		    break;
744         case ccProduce:
745             console->addStdMessage("UnitNoReqs");
746             break;
747         case ccUpgrade:
748             console->addStdMessage("UpgradeNoReqs");
749             break;
750         default:
751             break;
752         }
753         break;
754 	case crFailRes:
755         switch(cc){
756         case ccBuild:
757             console->addStdMessage("BuildingNoRes");
758 		    break;
759         case ccProduce:
760             console->addStdMessage("UnitNoRes");
761             break;
762         case ccUpgrade:
763             console->addStdMessage("UpgradeNoRes");
764             break;
765 		default:
766 			break;
767         }
768 		break;
769 
770     case crFailUndefined:
771         console->addStdMessage("InvalidOrder");
772         break;
773 
774     case crSomeFailed:
775         console->addStdMessage("SomeOrdersFailed");
776         break;
777     }
778 }
779 
isSharedCommandClass(CommandClass commandClass)780 bool Gui::isSharedCommandClass(CommandClass commandClass){
781     for(int i=0; i<selection.getCount(); ++i){
782 		const Unit *unit= selection.getUnit(i);
783         const CommandType *ct= unit->getType()->getFirstCtOfClass(commandClass);
784 		if(ct==NULL || !unit->getFaction()->reqsOk(ct))
785             return false;
786     }
787     return true;
788 }
789 
computeSelected(bool doubleClick)790 void Gui::computeSelected(bool doubleClick){
791 	Selection::UnitContainer units;
792 	Renderer::getInstance().computeSelected(units, selectionQuad.getPosDown(), selectionQuad.getPosUp());
793 	selectingBuilding= false;
794 	activeCommandType= NULL;
795 
796 	//select all units of the same type if double click
797 	if(doubleClick && units.size()==1){
798 		const Unit *refUnit= units.front();
799 		int factionIndex= refUnit->getFactionIndex();
800 		for(int i=0; i<world->getFaction(factionIndex)->getUnitCount(); ++i){
801 			Unit *unit= world->getFaction(factionIndex)->getUnit(i);
802 			if(unit->getPos().dist(refUnit->getPos())<doubleClickSelectionRadius &&
803 				unit->getType()==refUnit->getType())
804 			{
805 				units.push_back(unit);
806 			}
807 		}
808 	}
809 
810 	bool shiftDown= isKeyDown(vkShift);
811 	bool controlDown= isKeyDown(vkControl);
812 
813 	if(!shiftDown && !controlDown){
814 		selection.clear();
815 	}
816 
817 	if(!controlDown){
818 		selection.select(units);
819 	}
820 	else{
821 		selection.unSelect(units);
822 	}
823 }
824 
computeTarget(const Vec2i & screenPos,Vec2i & targetPos,const Unit * & targetUnit)825 bool Gui::computeTarget(const Vec2i &screenPos, Vec2i &targetPos, const Unit *&targetUnit){
826 	Selection::UnitContainer uc;
827 	Renderer &renderer= Renderer::getInstance();
828 	renderer.computeSelected(uc, screenPos, screenPos);
829 	validPosObjWorld= false;
830 
831 	if(!uc.empty()){
832 		targetUnit= uc.front();
833 		targetPos= targetUnit->getPos();
834 		return true;
835 	}
836 	else{
837 		targetUnit= NULL;
838 		if(renderer.computePosition(screenPos, targetPos)){
839 			validPosObjWorld= true;
840 			posObjWorld= targetPos;
841 			return true;
842 		}
843 		else{
844 			return false;
845 		}
846 	}
847 }
848 
849 }}//end namespace
850