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 "world.h"
13
14 #include <algorithm>
15 #include <cassert>
16
17 #include "config.h"
18 #include "faction.h"
19 #include "unit.h"
20 #include "game.h"
21 #include "logger.h"
22 #include "sound_renderer.h"
23 #include "game_settings.h"
24 #include "leak_dumper.h"
25
26 using namespace Shared::Graphics;
27 using namespace Shared::Util;
28
29 namespace Glest{ namespace Game{
30
31 // =====================================================
32 // class World
33 // =====================================================
34
35 const float World::airHeight= 5.f;
36
37 // ===================== PUBLIC ========================
38
World()39 World::World(){
40 Config &config= Config::getInstance();
41
42 fogOfWar= config.getBool("FogOfWar");
43 fogOfWarSmoothing= config.getBool("FogOfWarSmoothing");
44 fogOfWarSmoothingFrameSkip= config.getInt("FogOfWarSmoothingFrameSkip");
45
46 frameCount= 0;
47 nextUnitId= 0;
48
49 scriptManager= NULL;
50 }
51
end()52 void World::end(){
53 Logger::getInstance().add("World", true);
54
55 for(int i= 0; i<factions.size(); ++i){
56 factions[i].end();
57 }
58 //stats will be deleted by BattleEnd
59 }
60
61 // ========================== init ===============================================
62
init(Game * game,bool createUnits)63 void World::init(Game *game, bool createUnits){
64
65 scriptManager= game->getScriptManager();
66
67 unitUpdater.init(game);
68
69 initFactionTypes(game->getGameSettings());
70 initCells(); //must be done after knowing faction number and dimensions
71 initMap();
72 initSplattedTextures();
73
74 //minimap must be init after sum computation
75 initMinimap();
76 if(createUnits){
77 initUnits();
78 }
79 initExplorationState();
80 computeFow();
81 }
82
83 //load tileset
loadTileset(const string & dir,Checksum * checksum)84 void World::loadTileset(const string &dir, Checksum *checksum){
85 tileset.load(dir, checksum);
86 timeFlow.init(&tileset);
87 }
88
89 //load tech
loadTech(const string & dir,Checksum * checksum)90 void World::loadTech(const string &dir, Checksum *checksum){
91 techTree.load(dir, checksum);
92 }
93
94 //load map
loadMap(const string & path,Checksum * checksum)95 void World::loadMap(const string &path, Checksum *checksum){
96 checksum->addFile(path);
97 map.load(path, &techTree, &tileset);
98 }
99
100 //load map
loadScenario(const string & path,Checksum * checksum)101 void World::loadScenario(const string &path, Checksum *checksum){
102 checksum->addFile(path);
103 scenario.load(path);
104 }
105
106 // ==================== misc ====================
107
update()108 void World::update(){
109
110 ++frameCount;
111
112 //time
113 timeFlow.update();
114
115 //water effects
116 waterEffects.update();
117
118 //units
119 for(int i=0; i<getFactionCount(); ++i){
120 for(int j=0; j<getFaction(i)->getUnitCount(); ++j){
121 unitUpdater.updateUnit(getFaction(i)->getUnit(j));
122 }
123 }
124
125 //undertake the dead
126 for(int i=0; i<getFactionCount(); ++i){
127 for(int j=0; j<getFaction(i)->getUnitCount(); ++j){
128 Unit *unit= getFaction(i)->getUnit(j);
129 if(unit->getToBeUndertaken()){
130 unit->undertake();
131 delete unit;
132 j--;
133 }
134 }
135 }
136
137 //food costs
138 for(int i=0; i<techTree.getResourceTypeCount(); ++i){
139 const ResourceType *rt= techTree.getResourceType(i);
140 if(rt->getClass()==rcConsumable && frameCount % (rt->getInterval()*GameConstants::updateFps)==0){
141 for(int i=0; i<getFactionCount(); ++i){
142 getFaction(i)->applyCostsOnInterval();
143 }
144 }
145 }
146
147 //fow smoothing
148 if(fogOfWarSmoothing && ((frameCount+1) % (fogOfWarSmoothingFrameSkip+1))==0){
149 float fogFactor= static_cast<float>(frameCount%GameConstants::updateFps)/GameConstants::updateFps;
150 minimap.updateFowTex(clamp(fogFactor, 0.f, 1.f));
151 }
152
153 //tick
154 if(frameCount%GameConstants::updateFps==0){
155 computeFow();
156 tick();
157 }
158 }
159
tick()160 void World::tick(){
161 if(!fogOfWarSmoothing){
162 minimap.updateFowTex(1.f);
163 }
164
165 //increase hp
166 for(int i=0; i<getFactionCount(); ++i){
167 for(int j=0; j<getFaction(i)->getUnitCount(); ++j){
168 getFaction(i)->getUnit(j)->tick();
169 }
170 }
171
172 //compute resources balance
173 for(int k=0; k<getFactionCount(); ++k){
174 Faction *faction= getFaction(k);
175
176 //for each resource
177 for(int i=0; i<techTree.getResourceTypeCount(); ++i){
178 const ResourceType *rt= techTree.getResourceType(i);
179
180 //if consumable
181 if(rt->getClass()==rcConsumable){
182 int balance= 0;
183 for(int j=0; j<faction->getUnitCount(); ++j){
184
185 //if unit operative and has this cost
186 const Unit *u= faction->getUnit(j);
187 if(u->isOperative()){
188 const Resource *r= u->getType()->getCost(rt);
189 if(r!=NULL){
190 balance-= u->getType()->getCost(rt)->getAmount();
191 }
192 }
193 }
194 faction->setResourceBalance(rt, balance);
195 }
196 }
197 }
198 }
199
findUnitById(int id)200 Unit* World::findUnitById(int id){
201 for(int i= 0; i<getFactionCount(); ++i){
202 Faction* faction= getFaction(i);
203
204 for(int j= 0; j<faction->getUnitCount(); ++j){
205 Unit* unit= faction->getUnit(j);
206
207 if(unit->getId()==id){
208 return unit;
209 }
210 }
211 }
212 return NULL;
213 }
214
findUnitTypeById(const FactionType * factionType,int id)215 const UnitType* World::findUnitTypeById(const FactionType* factionType, int id){
216 for(int i= 0; i<factionType->getUnitTypeCount(); ++i){
217 const UnitType* unitType= factionType->getUnitType(i);
218
219 if(unitType->getId()==id){
220 return unitType;
221 }
222 }
223 return NULL;
224 }
225
226 //looks for a place for a unit around a start lociacion, returns true if succeded
placeUnit(const Vec2i & startLoc,int radius,Unit * unit,bool spaciated)227 bool World::placeUnit(const Vec2i &startLoc, int radius, Unit *unit, bool spaciated){
228 bool freeSpace;
229 int size= unit->getType()->getSize();
230 Field currField= unit->getCurrField();
231
232 for(int r=1; r<radius; r++){
233 for(int i=-r; i<r; ++i){
234 for(int j=-r; j<r; ++j){
235 Vec2i pos= Vec2i(i,j)+startLoc;
236 if(spaciated){
237 const int spacing= 2;
238 freeSpace= map.isFreeCells(pos-Vec2i(spacing), size+spacing*2, currField);
239 }
240 else{
241 freeSpace= map.isFreeCells(pos, size, currField);
242 }
243
244 if(freeSpace){
245 unit->setPos(pos);
246 unit->setMeetingPos(pos-Vec2i(1));
247 return true;
248 }
249 }
250 }
251 }
252 return false;
253 }
254
255 //clears a unit old position from map and places new position
moveUnitCells(Unit * unit)256 void World::moveUnitCells(Unit *unit){
257 Vec2i newPos= unit->getTargetPos();
258
259 //newPos must be free or the same pos as current
260 assert(map.getCell(unit->getPos())->getUnit(unit->getCurrField())==unit || map.isFreeCell(newPos, unit->getCurrField()));
261 map.clearUnitCells(unit, unit->getPos());
262 map.putUnitCells(unit, newPos);
263
264 //water splash
265 if(tileset.getWaterEffects() && unit->getCurrField()==fLand){
266 if(map.getSubmerged(map.getCell(unit->getLastPos()))){
267 for(int i=0; i<3; ++i){
268 waterEffects.addWaterSplash(
269 Vec2f(unit->getLastPos().x+random.randRange(-0.4f, 0.4f), unit->getLastPos().y+random.randRange(-0.4f, 0.4f)));
270 }
271 }
272 }
273 }
274
275 //returns the nearest unit that can store a type of resource given a position and a faction
nearestStore(const Vec2i & pos,int factionIndex,const ResourceType * rt)276 Unit *World::nearestStore(const Vec2i &pos, int factionIndex, const ResourceType *rt){
277 float currDist= infinity;
278 Unit *currUnit= NULL;
279
280 for(int i=0; i<getFaction(factionIndex)->getUnitCount(); ++i){
281 Unit *u= getFaction(factionIndex)->getUnit(i);
282 float tmpDist= u->getPos().dist(pos);
283 if(tmpDist<currDist && u->getType()->getStore(rt)>0 && u->isOperative()){
284 currDist= tmpDist;
285 currUnit= u;
286 }
287 }
288 return currUnit;
289 }
290
toRenderUnit(const Unit * unit,const Quad2i & visibleQuad) const291 bool World::toRenderUnit(const Unit *unit, const Quad2i &visibleQuad) const{
292 //a unit is rendered if it is in a visible cell or is attacking a unit in a visible cell
293 return
294 visibleQuad.isInside(unit->getPos()) &&
295 toRenderUnit(unit);
296 }
297
toRenderUnit(const Unit * unit) const298 bool World::toRenderUnit(const Unit *unit) const{
299
300 return
301 map.getSurfaceCell(Map::toSurfCoords(unit->getCenteredPos()))->isVisible(thisTeamIndex) ||
302 (unit->getCurrSkill()->getClass()==scAttack &&
303 map.getSurfaceCell(Map::toSurfCoords(unit->getTargetPos()))->isVisible(thisTeamIndex));
304 }
305
createUnit(const string & unitName,int factionIndex,const Vec2i & pos)306 void World::createUnit(const string &unitName, int factionIndex, const Vec2i &pos){
307 if(factionIndex<factions.size()){
308 Faction* faction= &factions[factionIndex];
309 const FactionType* ft= faction->getType();
310 const UnitType* ut= ft->getUnitType(unitName);
311
312 Unit* unit= new Unit(getNextUnitId(), pos, ut, faction, &map);
313 if(placeUnit(pos, generationArea, unit, true)){
314 unit->create(true);
315 unit->born();
316 scriptManager->onUnitCreated(unit);
317 }
318 else{
319 throw runtime_error("Unit cant be placed");
320 }
321 }
322 else
323 {
324 throw runtime_error("Invalid faction index in createUnitAtPosition: " + intToStr(factionIndex));
325 }
326 }
327
giveResource(const string & resourceName,int factionIndex,int amount)328 void World::giveResource(const string &resourceName, int factionIndex, int amount){
329 if(factionIndex<factions.size()){
330 Faction* faction= &factions[factionIndex];
331 const ResourceType* rt= techTree.getResourceType(resourceName);
332 faction->incResourceAmount(rt, amount);
333 }
334 else
335 {
336 throw runtime_error("Invalid faction index in giveResource: " + intToStr(factionIndex));
337 }
338 }
339
givePositionCommand(int unitId,const string & commandName,const Vec2i & pos)340 void World::givePositionCommand(int unitId, const string &commandName, const Vec2i &pos){
341 Unit* unit= findUnitById(unitId);
342 if(unit!=NULL){
343 CommandClass cc;
344
345 if(commandName=="move"){
346 cc= ccMove;
347 }
348 else if(commandName=="attack"){
349 cc= ccAttack;
350 }
351 else{
352 throw runtime_error("Invalid position commmand: " + commandName);
353 }
354
355 unit->giveCommand(new Command( unit->getType()->getFirstCtOfClass(cc), pos ));
356 }
357 }
358
giveProductionCommand(int unitId,const string & producedName)359 void World::giveProductionCommand(int unitId, const string &producedName){
360 Unit *unit= findUnitById(unitId);
361 if(unit!=NULL){
362 const UnitType *ut= unit->getType();
363
364 //Search for a command that can produce the unit
365 for(int i= 0; i<ut->getCommandTypeCount(); ++i){
366 const CommandType* ct= ut->getCommandType(i);
367 if(ct->getClass()==ccProduce){
368 const ProduceCommandType *pct= static_cast<const ProduceCommandType*>(ct);
369 if(pct->getProducedUnit()->getName()==producedName){
370 unit->giveCommand(new Command(pct));
371 break;
372 }
373 }
374 }
375 }
376 }
377
giveUpgradeCommand(int unitId,const string & upgradeName)378 void World::giveUpgradeCommand(int unitId, const string &upgradeName){
379 Unit *unit= findUnitById(unitId);
380 if(unit!=NULL){
381 const UnitType *ut= unit->getType();
382
383 //Search for a command that can produce the unit
384 for(int i= 0; i<ut->getCommandTypeCount(); ++i){
385 const CommandType* ct= ut->getCommandType(i);
386 if(ct->getClass()==ccUpgrade){
387 const UpgradeCommandType *uct= static_cast<const UpgradeCommandType*>(ct);
388 if(uct->getProducedUpgrade()->getName()==upgradeName){
389 unit->giveCommand(new Command(uct));
390 break;
391 }
392 }
393 }
394 }
395 }
396
397
getResourceAmount(const string & resourceName,int factionIndex)398 int World::getResourceAmount(const string &resourceName, int factionIndex){
399 if(factionIndex<factions.size()){
400 Faction* faction= &factions[factionIndex];
401 const ResourceType* rt= techTree.getResourceType(resourceName);
402 return faction->getResource(rt)->getAmount();
403 }
404 else
405 {
406 throw runtime_error("Invalid faction index in giveResource: " + intToStr(factionIndex));
407 }
408 }
409
getStartLocation(int factionIndex)410 Vec2i World::getStartLocation(int factionIndex){
411 if(factionIndex<factions.size()){
412 Faction* faction= &factions[factionIndex];
413 return map.getStartLocation(faction->getStartLocationIndex());
414 }
415 else
416 {
417 throw runtime_error("Invalid faction index in getStartLocation: " + intToStr(factionIndex));
418 }
419 }
420
getUnitPosition(int unitId)421 Vec2i World::getUnitPosition(int unitId){
422 Unit* unit= findUnitById(unitId);
423 if(unit==NULL){
424 throw runtime_error("Can not find unit to get position");
425 }
426 return unit->getPos();
427 }
428
getUnitFactionIndex(int unitId)429 int World::getUnitFactionIndex(int unitId){
430 Unit* unit= findUnitById(unitId);
431 if(unit==NULL){
432 throw runtime_error("Can not find unit to get position");
433 }
434 return unit->getFactionIndex();
435 }
436
getUnitCount(int factionIndex)437 int World::getUnitCount(int factionIndex){
438 if(factionIndex<factions.size()){
439 Faction* faction= &factions[factionIndex];
440 int count= 0;
441
442 for(int i= 0; i<faction->getUnitCount(); ++i){
443 const Unit* unit= faction->getUnit(i);
444 if(unit->isAlive()){
445 ++count;
446 }
447 }
448 return count;
449 }
450 else
451 {
452 throw runtime_error("Invalid faction index in getUnitCount: " + intToStr(factionIndex));
453 }
454 }
455
getUnitCountOfType(int factionIndex,const string & typeName)456 int World::getUnitCountOfType(int factionIndex, const string &typeName){
457 if(factionIndex<factions.size()){
458 Faction* faction= &factions[factionIndex];
459 int count= 0;
460
461 for(int i= 0; i< faction->getUnitCount(); ++i){
462 const Unit* unit= faction->getUnit(i);
463 if(unit->isAlive() && unit->getType()->getName()==typeName){
464 ++count;
465 }
466 }
467 return count;
468 }
469 else
470 {
471 throw runtime_error("Invalid faction index in getUnitCountOfType: " + intToStr(factionIndex));
472 }
473 }
474
475 // ==================== PRIVATE ====================
476
477 // ==================== private init ====================
478
479 //init basic cell state
initCells()480 void World::initCells(){
481
482 Logger::getInstance().add("State cells", true);
483 for(int i=0; i<map.getSurfaceW(); ++i){
484 for(int j=0; j<map.getSurfaceH(); ++j){
485
486 SurfaceCell *sc= map.getSurfaceCell(i, j);
487
488 sc->setFowTexCoord(Vec2f(
489 i/(next2Power(map.getSurfaceW())-1.f),
490 j/(next2Power(map.getSurfaceH())-1.f)));
491
492 for(int k=0; k<GameConstants::maxPlayers; k++){
493 sc->setExplored(k, false);
494 sc->setVisible(k, 0);
495 }
496 }
497 }
498 }
499
500 //init surface textures
initSplattedTextures()501 void World::initSplattedTextures(){
502 for(int i=0; i<map.getSurfaceW()-1; ++i){
503 for(int j=0; j<map.getSurfaceH()-1; ++j){
504 Vec2f coord;
505 const Texture2D *texture;
506 SurfaceCell *sc00= map.getSurfaceCell(i, j);
507 SurfaceCell *sc10= map.getSurfaceCell(i+1, j);
508 SurfaceCell *sc01= map.getSurfaceCell(i, j+1);
509 SurfaceCell *sc11= map.getSurfaceCell(i+1, j+1);
510 tileset.addSurfTex(
511 sc00->getSurfaceType(),
512 sc10->getSurfaceType(),
513 sc01->getSurfaceType(),
514 sc11->getSurfaceType(),
515 coord, texture);
516 sc00->setSurfTexCoord(coord);
517 sc00->setSurfaceTexture(texture);
518 }
519 }
520 }
521
522 //creates each faction looking at each faction name contained in GameSettings
initFactionTypes(GameSettings * gs)523 void World::initFactionTypes(GameSettings *gs){
524 Logger::getInstance().add("Faction types", true);
525
526 if(gs->getFactionCount() > map.getMaxPlayers()){
527 throw runtime_error("This map only supports "+intToStr(map.getMaxPlayers())+" players");
528 }
529
530 //create stats
531 stats.init(gs->getFactionCount(), gs->getThisFactionIndex(), gs->getDescription());
532
533 //create factions
534 this->thisFactionIndex= gs->getThisFactionIndex();
535 factions.resize(gs->getFactionCount());
536 for(int i=0; i<factions.size(); ++i){
537 const FactionType *ft= techTree.getType(gs->getFactionTypeName(i));
538 factions[i].init(
539 ft, gs->getFactionControl(i), &techTree, i, gs->getTeam(i),
540 gs->getStartLocationIndex(i), i==thisFactionIndex, gs->getDefaultResources());
541
542 stats.setTeam(i, gs->getTeam(i));
543 stats.setFactionTypeName(i, formatString(gs->getFactionTypeName(i)));
544 stats.setControl(i, gs->getFactionControl(i));
545 }
546
547 thisTeamIndex= getFaction(thisFactionIndex)->getTeam();
548 }
549
initMinimap()550 void World::initMinimap(){
551 minimap.init(map.getW(), map.getH(), this);
552 Logger::getInstance().add("Compute minimap surface", true);
553 }
554
555 //place units randomly aroud start location
initUnits()556 void World::initUnits(){
557
558 Logger::getInstance().add("Generate elements", true);
559
560 //put starting units
561 for(int i=0; i<getFactionCount(); ++i){
562 Faction *f= &factions[i];
563 const FactionType *ft= f->getType();
564 for(int j=0; j<ft->getStartingUnitCount(); ++j){
565 const UnitType *ut= ft->getStartingUnit(j);
566 int initNumber= ft->getStartingUnitAmount(j);
567 for(int l=0; l<initNumber; l++){
568 Unit *unit= new Unit(getNextUnitId(), Vec2i(0), ut, f, &map);
569 int startLocationIndex= f->getStartLocationIndex();
570
571 if(placeUnit(map.getStartLocation(startLocationIndex), generationArea, unit, true)){
572 unit->create(true);
573 unit->born();
574 }
575 else{
576 throw runtime_error("Unit cant be placed, this error is caused because there is no enough place to put the units near its start location, make a better map: "+unit->getType()->getName() + " Faction: "+intToStr(i));
577 }
578 if(unit->getType()->hasSkillClass(scBeBuilt)){
579 map.flatternTerrain(unit);
580 }
581 }
582 }
583 }
584 map.computeNormals();
585 map.computeInterpolatedHeights();
586 }
587
initMap()588 void World::initMap(){
589 map.init();
590 }
591
initExplorationState()592 void World::initExplorationState(){
593 if(!fogOfWar){
594 for(int i=0; i<map.getSurfaceW(); ++i){
595 for(int j=0; j<map.getSurfaceH(); ++j){
596 map.getSurfaceCell(i, j)->setVisible(thisTeamIndex, true);
597 map.getSurfaceCell(i, j)->setExplored(thisTeamIndex, true);
598 }
599 }
600 }
601 }
602
603
604 // ==================== exploration ====================
605
exploreCells(const Vec2i & newPos,int sightRange,int teamIndex)606 void World::exploreCells(const Vec2i &newPos, int sightRange, int teamIndex){
607
608 Vec2i newSurfPos= Map::toSurfCoords(newPos);
609 int surfSightRange= sightRange/Map::cellScale+1;
610
611 //explore
612 for(int i=-surfSightRange-indirectSightRange-1; i<=surfSightRange+indirectSightRange+1; ++i){
613 for(int j=-surfSightRange-indirectSightRange-1; j<=surfSightRange+indirectSightRange+1; ++j){
614 Vec2i currRelPos= Vec2i(i, j);
615 Vec2i currPos= newSurfPos + currRelPos;
616 if(map.isInsideSurface(currPos)){
617
618 SurfaceCell *sc= map.getSurfaceCell(currPos);
619
620 //explore
621 if(Vec2i(0).dist(currRelPos) < surfSightRange+indirectSightRange+1){
622 sc->setExplored(teamIndex, true);
623 }
624
625 //visible
626 if(Vec2i(0).dist(currRelPos) < surfSightRange){
627 sc->setVisible(teamIndex, true);
628 }
629 }
630 }
631 }
632 }
633
634 //computes the fog of war texture, contained in the minimap
computeFow()635 void World::computeFow(){
636
637 //reset texture
638 minimap.resetFowTex();
639
640 //reset cells
641 for(int i=0; i<map.getSurfaceW(); ++i){
642 for(int j=0; j<map.getSurfaceH(); ++j){
643 for(int k=0; k<GameConstants::maxPlayers; ++k){
644 if(fogOfWar || k!=thisTeamIndex){
645 map.getSurfaceCell(i, j)->setVisible(k, false);
646 }
647 }
648 }
649 }
650
651 //compute cells
652 for(int i=0; i<getFactionCount(); ++i){
653 for(int j=0; j<getFaction(i)->getUnitCount(); ++j){
654 Unit *unit= getFaction(i)->getUnit(j);
655
656 //exploration
657 if(unit->isOperative()){
658 exploreCells(unit->getCenteredPos(), unit->getType()->getSight(), unit->getTeam());
659 }
660 }
661 }
662
663 //fire
664 for(int i=0; i<getFactionCount(); ++i){
665 for(int j=0; j<getFaction(i)->getUnitCount(); ++j){
666 Unit *unit= getFaction(i)->getUnit(j);
667
668 //fire
669 ParticleSystem *fire= unit->getFire();
670 if(fire!=NULL){
671 fire->setActive(map.getSurfaceCell(Map::toSurfCoords(unit->getPos()))->isVisible(thisTeamIndex));
672 }
673 }
674 }
675
676 //compute texture
677 for(int i=0; i<getFactionCount(); ++i){
678 Faction *faction= getFaction(i);
679 if(faction->getTeam()==thisTeamIndex){
680 for(int j=0; j<faction->getUnitCount(); ++j){
681 const Unit *unit= faction->getUnit(j);
682 if(unit->isOperative()){
683 int sightRange= unit->getType()->getSight();
684
685 //iterate through all cells
686 PosCircularIterator pci(&map, unit->getPos(), sightRange+indirectSightRange);
687 while(pci.next()){
688 Vec2i pos= pci.getPos();
689 Vec2i surfPos= Map::toSurfCoords(pos);
690
691
692 //compute max alpha
693 float maxAlpha;
694 if(surfPos.x>1 && surfPos.y>1 && surfPos.x<map.getSurfaceW()-2 && surfPos.y<map.getSurfaceH()-2){
695 maxAlpha= 1.f;
696 }
697 else if(surfPos.x>0 && surfPos.y>0 && surfPos.x<map.getSurfaceW()-1 && surfPos.y<map.getSurfaceH()-1){
698 maxAlpha= 0.3f;
699 }
700 else{
701 maxAlpha= 0.0f;
702 }
703
704 //compute alpha
705 float alpha;
706 float dist= unit->getPos().dist(pos);
707 if(dist>sightRange){
708 alpha= clamp(1.f-(dist-sightRange)/(indirectSightRange), 0.f, maxAlpha);
709 }
710 else{
711 alpha= maxAlpha;
712 }
713 minimap.incFowTextureAlphaSurface(surfPos, alpha);
714 }
715 }
716 }
717 }
718 }
719 }
720
721 }}//end namespace
722