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