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