1 // ==============================================================
2 // ==============================================================
3 // This file is part of Glest (www.glest.org)
4 //
5 // Copyright (C) 2001-2008 Martiño Figueroa
6 //
7 // You can redistribute this code and/or modify it under
8 // the terms of the GNU General Public License as published
9 // by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version
11 // ==============================================================
12
13 #include "map.h"
14
15 #include <cassert>
16
17 #include "tileset.h"
18 #include "unit.h"
19 #include "resource.h"
20 #include "logger.h"
21 #include "tech_tree.h"
22 #include "config.h"
23 #include "util.h"
24 #include "game_settings.h"
25 #include "platform_util.h"
26 #include "faction.h"
27 #include "command.h"
28 #include "map_preview.h"
29 #include "world.h"
30 #include "byte_order.h"
31 #include "leak_dumper.h"
32
33 using namespace Shared::Graphics;
34 using namespace Shared::Util;
35 using namespace Shared::Platform;
36
37 namespace Glest{ namespace Game{
38
39 // =====================================================
40 // class Cell
41 // =====================================================
42
Cell()43 Cell::Cell() {
44 //game data
45 for(int i = 0; i < fieldCount; ++i) {
46 units[i]= NULL;
47 unitsWithEmptyCellMap[i]=NULL;
48 }
49 height= 0;
50 }
51
52 // ==================== misc ====================
53
54 //returns if the cell is free
55
56 //returns if the cell is free
57
saveGame(XmlNode * rootNode,int index) const58 void Cell::saveGame(XmlNode *rootNode, int index) const {
59 bool saveCell = false;
60 if(saveCell == false) {
61 for(unsigned int i = 0; i < fieldCount; ++i) {
62 if(units[i] != NULL) {
63 saveCell = true;
64 break;
65 }
66 if(unitsWithEmptyCellMap[i] != NULL) {
67 saveCell = true;
68 break;
69 }
70 }
71 }
72
73 if(saveCell == true) {
74 std::map<string,string> mapTagReplacements;
75 XmlNode *cellNode = rootNode->addChild("Cell" + intToStr(index));
76 cellNode->addAttribute("index",intToStr(index), mapTagReplacements);
77
78 // Unit *units[fieldCount]; //units on this cell
79 for(unsigned int i = 0; i < fieldCount; ++i) {
80 if(units[i] != NULL) {
81 XmlNode *unitsNode = cellNode->addChild("units");
82 unitsNode->addAttribute("field",intToStr(i), mapTagReplacements);
83 unitsNode->addAttribute("unitid",intToStr(units[i]->getId()), mapTagReplacements);
84 }
85 }
86 // Unit *unitsWithEmptyCellMap[fieldCount]; //units with an empty cellmap on this cell
87 for(unsigned int i = 0; i < fieldCount; ++i) {
88 if(unitsWithEmptyCellMap[i] != NULL) {
89 XmlNode *unitsWithEmptyCellMapNode = cellNode->addChild("unitsWithEmptyCellMap");
90 unitsWithEmptyCellMapNode->addAttribute("field",intToStr(i), mapTagReplacements);
91 unitsWithEmptyCellMapNode->addAttribute("unitid",intToStr(unitsWithEmptyCellMap[i]->getId()), mapTagReplacements);
92 }
93 }
94
95 // float height;
96 cellNode->addAttribute("height",floatToStr(getHeight(),6), mapTagReplacements);
97 }
98 }
99
loadGame(const XmlNode * rootNode,int index,World * world)100 void Cell::loadGame(const XmlNode *rootNode, int index, World *world) {
101 if(rootNode->hasChild("Cell" + intToStr(index)) == true) {
102 const XmlNode *cellNode = rootNode->getChild("Cell" + intToStr(index));
103
104 unsigned int unitCount = (unsigned int)cellNode->getChildCount();
105 for(unsigned int i = 0; i < unitCount; ++i) {
106 if(cellNode->hasChildAtIndex("units",i) == true) {
107 const XmlNode *unitsNode = cellNode->getChild("units",i);
108 int field = unitsNode->getAttribute("field")->getIntValue();
109 int unitId = unitsNode->getAttribute("unitid")->getIntValue();
110 units[field] = world->findUnitById(unitId);
111 }
112 if(cellNode->hasChildAtIndex("unitsWithEmptyCellMap",i) == true) {
113 const XmlNode *unitsNode = cellNode->getChild("unitsWithEmptyCellMap",i);
114 int field = unitsNode->getAttribute("field")->getIntValue();
115 int unitId = unitsNode->getAttribute("unitid")->getIntValue();
116 unitsWithEmptyCellMap[field] = world->findUnitById(unitId);
117 }
118 }
119 }
120 }
121
122 // =====================================================
123 // class SurfaceCell
124 // =====================================================
125
SurfaceCell()126 SurfaceCell::SurfaceCell() {
127 object= NULL;
128 vertex= Vec3f(0.f);
129 normal= Vec3f(0.f, 1.f, 0.f);
130 surfaceType= -1;
131 surfaceTexture= NULL;
132 nearSubmerged = false;
133 cellChangedFromOriginalMapLoad = false;
134
135 for(int index = 0; index < GameConstants::maxPlayers + GameConstants::specialFactions; ++index) {
136 setVisible(index,false);
137 setExplored(index,false);
138 }
139 }
140
~SurfaceCell()141 SurfaceCell::~SurfaceCell() {
142 delete object;
143 object=NULL;
144 }
145
end()146 void SurfaceCell::end(){
147 if(object!=NULL){
148 object->end();
149 }
150 }
151
deleteResource()152 void SurfaceCell::deleteResource() {
153 cellChangedFromOriginalMapLoad = true;
154
155 delete object;
156 object= NULL;
157 }
158
setHeight(float height,bool cellChangedFromOriginalMapLoadValue)159 void SurfaceCell::setHeight(float height, bool cellChangedFromOriginalMapLoadValue) {
160 height = truncateDecimal<float>(height);
161 vertex.y= height;
162 if(cellChangedFromOriginalMapLoadValue == true) {
163 this->cellChangedFromOriginalMapLoad = true;
164 }
165 }
166
decAmount(int value)167 bool SurfaceCell::decAmount(int value) {
168 cellChangedFromOriginalMapLoad = true;
169
170 return object->getResource()->decAmount(value);
171 }
setExplored(int teamIndex,bool explored)172 void SurfaceCell::setExplored(int teamIndex, bool explored) {
173 if(teamIndex < 0 || teamIndex >= GameConstants::maxPlayers + GameConstants::specialFactions) {
174 char szBuf[8096]="";
175 snprintf(szBuf,8096,"Invalid value for teamIndex [%d]",teamIndex);
176 printf("%s\n",szBuf);
177 throw megaglest_runtime_error(szBuf);
178 }
179
180 this->explored[teamIndex]= explored;
181 //printf("Setting explored to %d for teamIndex %d\n",explored,teamIndex);
182 }
183
setVisible(int teamIndex,bool visible)184 void SurfaceCell::setVisible(int teamIndex, bool visible) {
185 if(teamIndex < 0 || teamIndex >= GameConstants::maxPlayers + GameConstants::specialFactions) {
186 char szBuf[8096]="";
187 snprintf(szBuf,8096,"Invalid value for teamIndex [%d]",teamIndex);
188 printf("%s\n",szBuf);
189 throw megaglest_runtime_error(szBuf);
190 }
191
192 this->visible[teamIndex]= visible;
193
194 if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true &&
195 SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynchMax).enabled == true) {
196 char szBuf[8096]="";
197 snprintf(szBuf,8096,"In setVisible() teamIndex %d visible %d",teamIndex,visible);
198
199 // if(frameIndex < 0) {
200 // unit->logSynchData(__FILE__,__LINE__,szBuf);
201 // }
202 // else {
203 // unit->logSynchDataThreaded(__FILE__,__LINE__,szBuf);
204 // }
205
206 if(Thread::isCurrentThreadMainThread()) {
207 //unit->logSynchDataThreaded(__FILE__,__LINE__,szBuf);
208 SystemFlags::OutputDebug(SystemFlags::debugWorldSynch,szBuf);
209 }
210 else {
211 //unit->logSynchData(__FILE__,__LINE__,szBuf);
212 printf("%s",szBuf);
213 }
214
215 }
216
217 }
218
isVisibleString() const219 string SurfaceCell::isVisibleString() const {
220 string result = "isVisibleList = ";
221 for(int index = 0; index < GameConstants::maxPlayers + GameConstants::specialFactions; ++index) {
222 result += string(visible[index] ? "true" : "false");
223 }
224 return result;
225 }
isExploredString() const226 string SurfaceCell::isExploredString() const {
227 string result = "isExploredList = ";
228 for(int index = 0; index < GameConstants::maxPlayers + GameConstants::specialFactions; ++index) {
229 result += string(explored[index] ? "true" : "false");
230 }
231 return result;
232 }
233
saveGame(XmlNode * rootNode,int index) const234 void SurfaceCell::saveGame(XmlNode *rootNode,int index) const {
235 bool saveCell = (this->getCellChangedFromOriginalMapLoad() == true);
236
237 if(saveCell == true) {
238 std::map<string,string> mapTagReplacements;
239 XmlNode *surfaceCellNode = rootNode->addChild("SurfaceCell" + intToStr(index));
240 surfaceCellNode->addAttribute("index",intToStr(index), mapTagReplacements);
241
242 // //geometry
243 // Vec3f vertex;
244 surfaceCellNode->addAttribute("vertex",vertex.getString(), mapTagReplacements);
245 // Vec3f normal;
246 //surfaceCellNode->addAttribute("normal",normal.getString(), mapTagReplacements);
247 // Vec3f color;
248 //surfaceCellNode->addAttribute("color",color.getString(), mapTagReplacements);
249 //
250 // //tex coords
251 // Vec2f fowTexCoord; //tex coords for TEXTURE1 when multitexturing and fogOfWar
252 //surfaceCellNode->addAttribute("fowTexCoord",fowTexCoord.getString(), mapTagReplacements);
253 // Vec2f surfTexCoord; //tex coords for TEXTURE0
254 //surfaceCellNode->addAttribute("surfTexCoord",surfTexCoord.getString(), mapTagReplacements);
255 // //surface
256 // int surfaceType;
257 //surfaceCellNode->addAttribute("surfaceType",intToStr(surfaceType), mapTagReplacements);
258 // const Texture2D *surfaceTexture;
259 //
260 // //object & resource
261 // Object *object;
262 if(object != NULL) {
263 object->saveGame(surfaceCellNode);
264 }
265 else {
266 XmlNode *objectNode = surfaceCellNode->addChild("Object");
267 objectNode->addAttribute("isDeleted",intToStr(true), mapTagReplacements);
268 }
269 // //visibility
270 // bool visible[GameConstants::maxPlayers + GameConstants::specialFactions];
271 // for(unsigned int i = 0; i < GameConstants::maxPlayers; ++i) {
272 // if(visible[i] == true) {
273 // XmlNode *visibleNode = surfaceCellNode->addChild("visible");
274 // visibleNode->addAttribute("index",intToStr(i), mapTagReplacements);
275 // visibleNode->addAttribute("value",intToStr(visible[i]), mapTagReplacements);
276 // }
277 // }
278 // // bool explored[GameConstants::maxPlayers + GameConstants::specialFactions];
279 // for(unsigned int i = 0; i < GameConstants::maxPlayers; ++i) {
280 // if(explored[i] == true) {
281 // XmlNode *exploredNode = surfaceCellNode->addChild("explored");
282 // exploredNode->addAttribute("index",intToStr(i), mapTagReplacements);
283 // exploredNode->addAttribute("value",intToStr(explored[i]), mapTagReplacements);
284 // }
285 // }
286
287 // //cache
288 // bool nearSubmerged;
289 //surfaceCellNode->addAttribute("nearSubmerged",intToStr(nearSubmerged), mapTagReplacements);
290 }
291 }
292
loadGame(const XmlNode * rootNode,int index,World * world)293 void SurfaceCell::loadGame(const XmlNode *rootNode, int index, World *world) {
294 if(rootNode->hasChild("SurfaceCell" + intToStr(index)) == true) {
295 const XmlNode *surfaceCellNode = rootNode->getChild("SurfaceCell" + intToStr(index));
296
297 if(surfaceCellNode->hasAttribute("vertex") == true) {
298 vertex = Vec3f::strToVec3(surfaceCellNode->getAttribute("vertex")->getValue());
299 }
300
301 //int visibleCount = cellNode->getChildCount();
302 XmlNode *objectNode = surfaceCellNode->getChild("Object");
303 if(objectNode->hasAttribute("isDeleted") == true) {
304 this->deleteResource();
305 }
306 else {
307 object->loadGame(surfaceCellNode,world->getTechTree());
308 }
309
310 //printf("Loading game, sc index [%d][%d]\n",index,visibleCount);
311
312 // for(unsigned int i = 0; i < visibleCount; ++i) {
313 // if(cellNode->hasChildAtIndex("visible",i) == true) {
314 // const XmlNode *visibleNode = cellNode->getChild("visible",i);
315 // int indexCell = visibleNode->getAttribute("index")->getIntValue();
316 // bool value = visibleNode->getAttribute("value")->getIntValue();
317 // visible[indexCell] = value;
318 //
319 // //printf("Loading game, sc visible index [%d][%d][%d]\n",index,indexCell,value);
320 // }
321 // if(cellNode->hasChildAtIndex("explored",i) == true) {
322 // const XmlNode *exploredNode = cellNode->getChild("explored",i);
323 // int indexCell = exploredNode->getAttribute("index")->getIntValue();
324 // bool value = exploredNode->getAttribute("value")->getIntValue();
325 // explored[indexCell] = value;
326 //
327 // //printf("Loading game, sc explored cell index [%d] exploredIndex [%d] value [%d]\n",index,indexCell,value);
328 // }
329 // }
330 }
331 }
332 // =====================================================
333 // class Map
334 // =====================================================
335
336 // ===================== PUBLIC ========================
337
338 const int Map::cellScale= 2;
339 const int Map::mapScale= 2;
340
Map()341 Map::Map() {
342 cells= NULL;
343 surfaceCells= NULL;
344 startLocations= NULL;
345
346 title="";
347 waterLevel=0;
348 heightFactor=0;
349 cliffLevel=0;
350 cameraHeight=0;
351 w=0;
352 h=0;
353 surfaceW=0;
354 surfaceH=0;
355 surfaceSize=(surfaceW * surfaceH);
356 maxPlayers=0;
357 maxMapHeight=0;
358 }
359
~Map()360 Map::~Map() {
361 Logger::getInstance().add(Lang::getInstance().getString("LogScreenGameUnLoadingMapCells","",true), true);
362
363 delete [] cells;
364 cells = NULL;
365 delete [] surfaceCells;
366 surfaceCells = NULL;
367 delete [] startLocations;
368 startLocations = NULL;
369 }
370
end()371 void Map::end(){
372 if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
373 Logger::getInstance().add(Lang::getInstance().getString("LogScreenGameUnLoadingMap","",true), true);
374 //read heightmap
375 for(int j = 0; j < surfaceH; ++j) {
376 for(int i = 0; i < surfaceW; ++i) {
377 getSurfaceCell(i, j)->end();
378 }
379 }
380 if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
381 }
382
getStartLocation(int locationIndex) const383 Vec2i Map::getStartLocation(int locationIndex) const {
384 if(locationIndex >= maxPlayers) {
385 char szBuf[8096]="";
386 snprintf(szBuf,8096,"locationIndex >= maxPlayers [%d] [%d]",locationIndex, maxPlayers);
387 printf("%s\n",szBuf);
388 throw megaglest_runtime_error(szBuf);
389 //assert(locationIndex < maxPlayers);
390 }
391 else if(startLocations == NULL) {
392 throw megaglest_runtime_error("startLocations == NULL");
393 }
394
395 return startLocations[locationIndex];
396 }
397
load(const string & path,TechTree * techTree,Tileset * tileset)398 Checksum Map::load(const string &path, TechTree *techTree, Tileset *tileset) {
399 Checksum mapChecksum;
400 try{
401 #ifdef WIN32
402 FILE *f= _wfopen(utf8_decode(path).c_str(), L"rb");
403 #else
404 FILE *f = fopen(path.c_str(), "rb");
405 #endif
406 if(f != NULL) {
407 mapFile = path;
408
409 mapChecksum.addFile(path);
410 checksumValue.addFile(path);
411 //read header
412 MapFileHeader header;
413 size_t readBytes = fread(&header, sizeof(MapFileHeader), 1, f);
414 if(readBytes != 1) {
415 throw megaglest_runtime_error("Invalid map header detected for file: " + path);
416 }
417 fromEndianMapFileHeader(header);
418
419 if(next2Power(header.width) != header.width){
420 throw megaglest_runtime_error("Map width is not a power of 2");
421 }
422
423 if(next2Power(header.height) != header.height){
424 throw megaglest_runtime_error("Map height is not a power of 2");
425 }
426
427 heightFactor= header.heightFactor;
428 if(heightFactor>100){
429 heightFactor=heightFactor/100;
430 heightFactor = truncateDecimal<float>(heightFactor,6);
431 }
432 waterLevel= static_cast<float>((header.waterLevel-0.01f)/heightFactor);
433 waterLevel = truncateDecimal<float>(waterLevel,6);
434 title= header.title;
435 maxPlayers= header.maxFactions;
436
437 surfaceW= header.width;
438 surfaceH= header.height;
439 surfaceSize=(surfaceW * surfaceH);
440
441 w= surfaceW*cellScale;
442 h= surfaceH*cellScale;
443 cliffLevel = 0;
444 cameraHeight = 0;
445 if(header.version==1){
446 //desc = header.description;
447 }
448 else if(header.version==2){
449 //desc = header.version2.short_desc;
450 if(header.version2.cliffLevel > 0 && header.version2.cliffLevel < 5000){
451 cliffLevel=static_cast<float>((header.version2.cliffLevel-0.01f)/(heightFactor));
452 cliffLevel = truncateDecimal<float>(cliffLevel,6);
453 }
454 if(header.version2.cameraHeight > 0 && header.version2.cameraHeight < 5000) {
455 cameraHeight = header.version2.cameraHeight;
456 }
457 }
458
459 //start locations
460 startLocations= new Vec2i[maxPlayers];
461 for(int i=0; i < maxPlayers; ++i) {
462 int x=0, y=0;
463 readBytes = fread(&x, sizeof(int32), 1, f);
464 if(readBytes != 1) {
465 char szBuf[8096]="";
466 snprintf(szBuf,8096,"fread returned wrong size = " MG_SIZE_T_SPECIFIER " on line: %d.",readBytes,__LINE__);
467 throw megaglest_runtime_error(szBuf);
468 }
469 x = ::Shared::PlatformByteOrder::fromCommonEndian(x);
470
471 readBytes = fread(&y, sizeof(int32), 1, f);
472 if(readBytes != 1) {
473 char szBuf[8096]="";
474 snprintf(szBuf,8096,"fread returned wrong size = " MG_SIZE_T_SPECIFIER " on line: %d.",readBytes,__LINE__);
475 throw megaglest_runtime_error(szBuf);
476 }
477 y = ::Shared::PlatformByteOrder::fromCommonEndian(y);
478
479 startLocations[i]= Vec2i(x, y)*cellScale;
480 }
481
482 //cells
483 cells= new Cell[getCellArraySize()];
484 surfaceCells= new SurfaceCell[getSurfaceCellArraySize()];
485
486 //read heightmap
487 for(int j = 0; j < surfaceH; ++j) {
488 for(int i = 0; i < surfaceW; ++i) {
489 float32 alt=0;
490 readBytes = fread(&alt, sizeof(float32), 1, f);
491 if(readBytes != 1) {
492 char szBuf[8096]="";
493 snprintf(szBuf,8096,"fread returned wrong size = " MG_SIZE_T_SPECIFIER " on line: %d.",readBytes,__LINE__);
494 throw megaglest_runtime_error(szBuf);
495 }
496 alt = ::Shared::PlatformByteOrder::fromCommonEndian(alt);
497
498 SurfaceCell *sc= getSurfaceCell(i, j);
499 sc->setVertex(Vec3f(i*mapScale, alt / heightFactor, j*mapScale));
500 }
501 }
502
503 //read surfaces
504 for(int j = 0; j < surfaceH; ++j) {
505 for(int i = 0; i < surfaceW; ++i) {
506 int8 surf=0;
507 readBytes = fread(&surf, sizeof(int8), 1, f);
508 if(readBytes != 1) {
509 char szBuf[8096]="";
510 snprintf(szBuf,8096,"fread returned wrong size = " MG_SIZE_T_SPECIFIER " on line: %d.",readBytes,__LINE__);
511 throw megaglest_runtime_error(szBuf);
512 }
513 surf = ::Shared::PlatformByteOrder::fromCommonEndian(surf);
514
515 getSurfaceCell(i, j)->setSurfaceType(surf-1);
516 }
517 }
518
519 //read objects and resources
520 for(int j = 0; j < h; j += cellScale) {
521 for(int i = 0; i < w; i += cellScale) {
522
523 int8 objNumber=0;
524 readBytes = fread(&objNumber, sizeof(int8), 1, f);
525 if(readBytes != 1) {
526 char szBuf[8096]="";
527 snprintf(szBuf,8096,"fread returned wrong size = " MG_SIZE_T_SPECIFIER " on line: %d.",readBytes,__LINE__);
528 throw megaglest_runtime_error(szBuf);
529 }
530 objNumber = ::Shared::PlatformByteOrder::fromCommonEndian(objNumber);
531
532 SurfaceCell *sc= getSurfaceCell(toSurfCoords(Vec2i(i, j)));
533 if(objNumber <= 0) {
534 sc->setObject(NULL);
535 }
536 else if(objNumber <= Tileset::objCount) {
537 Object *o= new Object(tileset->getObjectType(objNumber-1), sc->getVertex(),Vec2i(i, j));
538 sc->setObject(o);
539 for(int k = 0; k < techTree->getResourceTypeCount(); ++k) {
540 const ResourceType *rt= techTree->getResourceType(k);
541 if(rt->getClass() == rcTileset && rt->getTilesetObject() == objNumber){
542 o->setResource(rt, Vec2i(i, j));
543 }
544 }
545 }
546 else{
547 const ResourceType *rt= techTree->getTechResourceType(objNumber - Tileset::objCount) ;
548 Object *o= new Object(NULL, sc->getVertex(),Vec2i(i, j));
549 o->setResource(rt, Vec2i(i, j));
550 sc->setObject(o);
551 }
552 }
553 }
554 if(f) fclose(f);
555 }
556 else {
557 throw megaglest_runtime_error("Can't open file");
558 }
559 }
560 catch(const exception &e){
561 SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,e.what());
562 throw megaglest_runtime_error("Error loading map: "+ path+ "\n"+ e.what());
563 }
564
565 return mapChecksum;
566 }
567
init(Tileset * tileset)568 void Map::init(Tileset *tileset) {
569 Logger::getInstance().add(Lang::getInstance().getString("LogScreenGameUnLoadingMap","",true), true);
570 maxMapHeight=0.0f;
571 smoothSurface(tileset);
572 computeNormals();
573 computeInterpolatedHeights();
574 computeNearSubmerged();
575 computeCellColors();
576 }
577
578
579 // ==================== is ====================
580
581 class FindBestPos {
582 public:
583 float distanceFromUnitNoAdjustment;
584 float distanceFromClickNoAdjustment;
585 Vec2i resourcePosNoAdjustment;
586 };
587
588 //returns if there is a resource next to a unit, in "resourcePos" is stored the relative position of the resource
isResourceNear(int frameIndex,const Vec2i & pos,const ResourceType * rt,Vec2i & resourcePos,int size,Unit * unit,bool fallbackToPeersHarvestingSameResource,Vec2i * resourceClickPos) const589 bool Map::isResourceNear(int frameIndex,const Vec2i &pos, const ResourceType *rt, Vec2i &resourcePos,
590 int size, Unit *unit, bool fallbackToPeersHarvestingSameResource,
591 Vec2i *resourceClickPos) const {
592
593 bool resourceNear = false;
594 float distanceFromUnit=-1;
595 float distanceFromClick=-1;
596
597 if(resourceClickPos) {
598 //printf("+++++++++ unit [%s - %d] pos = [%s] resourceClickPos [%s]\n",unit->getFullName().c_str(),unit->getId(),pos.getString().c_str(),resourceClickPos->getString().c_str());
599 }
600 for(int i = -size; i <= size; ++i) {
601 for(int j = -size; j <= size; ++j) {
602 Vec2i resPos = Vec2i(pos.x + i, pos.y + j);
603 if(resourceClickPos) {
604 resPos = Vec2i(resourceClickPos->x + i, resourceClickPos->y + j);
605 }
606 Vec2i surfCoords = toSurfCoords(resPos);
607
608 if(isInside(resPos) && isInsideSurface(surfCoords)) {
609 Resource *r= getSurfaceCell(surfCoords)->getResource();
610 if(r != NULL) {
611 if(r->getType() == rt) {
612 if(resourceClickPos) {
613 //printf("****** unit [%s - %d] resPos = [%s] resourceClickPos->dist(resPos) [%f] distanceFromClick [%f] unit->getCenteredPos().dist(resPos) [%f] distanceFromUnit [%f]\n",unit->getFullName().c_str(),unit->getId(),resPos.getString().c_str(),resourceClickPos->dist(resPos),distanceFromClick,unit->getCenteredPos().dist(resPos),distanceFromUnit);
614 }
615 if(resourceClickPos == NULL ||
616 (distanceFromClick < 0 || resourceClickPos->dist(resPos) <= distanceFromClick)) {
617 if(unit == NULL ||
618 (distanceFromUnit < 0 || unit->getCenteredPos().dist(resPos) <= distanceFromUnit)) {
619
620 bool isResourceNextToUnit = (resourceClickPos == NULL);
621 for(int i1 = -size; isResourceNextToUnit == false && i1 <= size; ++i1) {
622 for(int j1 = -size; j1 <= size; ++j1) {
623 Vec2i resPos1 = Vec2i(pos.x + i1, pos.y + j1);
624 if(resPos == resPos1) {
625 isResourceNextToUnit = true;
626 break;
627 }
628 }
629 }
630 if(isResourceNextToUnit == true) {
631 if(resourceClickPos != NULL) {
632 distanceFromClick = resourceClickPos->dist(resPos);
633 }
634 if(unit != NULL) {
635 distanceFromUnit = unit->getCenteredPos().dist(resPos);
636 }
637
638 resourcePos= pos + Vec2i(i,j);
639
640 if(unit == NULL || unit->isBadHarvestPos(resourcePos) == false) {
641 resourceNear = true;
642
643 if(resourceClickPos) {
644 //printf("@@@@@@@@ unit [%s - %d] resPos = [%s] resourceClickPos->dist(resPos) [%f] distanceFromClick [%f] unit->getCenteredPos().dist(resPos) [%f] distanceFromUnit [%f]\n",unit->getFullName().c_str(),unit->getId(),resPos.getString().c_str(),resourceClickPos->dist(resPos),distanceFromClick,unit->getCenteredPos().dist(resPos),distanceFromUnit);
645 }
646 }
647 }
648 }
649 }
650 }
651 }
652 }
653 }
654 }
655
656 if(resourceNear == false) {
657 if(fallbackToPeersHarvestingSameResource == true && unit != NULL) {
658 // Look for another unit that is currently harvesting the same resource
659 // type right now
660
661 // Check the faction cache for a known position where we can harvest
662 // this resource type
663 Vec2i result = unit->getFaction()->getClosestResourceTypeTargetFromCache(unit, rt,frameIndex);
664 if(result.x >= 0) {
665 resourcePos = result;
666
667 if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true) {
668 char szBuf[8096]="";
669 snprintf(szBuf,8096,"[found peer harvest pos] pos [%s] resourcePos [%s] unit->getFaction()->getCacheResourceTargetListSize() [%d]",
670 pos.getString().c_str(),resourcePos.getString().c_str(),unit->getFaction()->getCacheResourceTargetListSize());
671
672 if(frameIndex < 0) {
673 unit->logSynchData(__FILE__,__LINE__,szBuf);
674 }
675 else {
676 unit->logSynchDataThreaded(__FILE__,__LINE__,szBuf);
677 }
678 }
679
680 if(unit->getPos().dist(resourcePos) <= size) {
681 resourceNear = true;
682
683 if(resourceClickPos) {
684 //printf("###### unit [%s - %d]\n",unit->getFullName().c_str(),unit->getId());
685 }
686 }
687 }
688 }
689 }
690
691 if(resourceNear == false && resourceClickPos != NULL) {
692 std::vector<FindBestPos> bestPosList;
693
694 //if(resourceClickPos) {
695 //printf("^^^^^ unit [%s - %d]\n",unit->getFullName().c_str(),unit->getId());
696 //}
697
698 for(int i = -1; i <= 1; ++i) {
699 for(int j = -1; j <= 1; ++j) {
700 Vec2i resPos = Vec2i(resourceClickPos->x + i, resourceClickPos->y + j);
701 Vec2i surfCoords = toSurfCoords(resPos);
702
703 if(isInside(resPos) && isInsideSurface(surfCoords)) {
704 Resource *r= getSurfaceCell(surfCoords)->getResource();
705 if(r != NULL) {
706 if(r->getType() == rt) {
707 //printf("^^^^^^ unit [%s - %d] resPos = [%s] resourceClickPos->dist(resPos) [%f] distanceFromClick [%f] unit->getCenteredPos().dist(resPos) [%f] distanceFromUnit [%f]\n",unit->getFullName().c_str(),unit->getId(),resPos.getString().c_str(),resourceClickPos->dist(resPos),distanceFromClick,unit->getCenteredPos().dist(resPos),distanceFromUnit);
708
709 if(unit == NULL ||
710 (distanceFromUnit < 0 || unit->getCenteredPos().dist(resPos) <= (distanceFromUnit + 2.0))) {
711
712 if(resourceClickPos->dist(resPos) <= 1.0) {
713 if(unit != NULL) {
714 FindBestPos bestPosItem;
715
716 bestPosItem.distanceFromUnitNoAdjustment = unit->getCenteredPos().dist(resPos);
717 bestPosItem.distanceFromClickNoAdjustment =distanceFromClick = resourceClickPos->dist(resPos);
718 bestPosItem.resourcePosNoAdjustment = resPos;
719
720 bestPosList.push_back(bestPosItem);
721 }
722 }
723
724 //printf("!!!! unit [%s - %d] resPos = [%s] resourceClickPos->dist(resPos) [%f] distanceFromClick [%f] unit->getCenteredPos().dist(resPos) [%f] distanceFromUnit [%f]\n",unit->getFullName().c_str(),unit->getId(),resPos.getString().c_str(),resourceClickPos->dist(resPos),distanceFromClick,unit->getCenteredPos().dist(resPos),distanceFromUnit);
725 if(distanceFromClick < 0 || resourceClickPos->dist(resPos) <= distanceFromClick) {
726 if(resourceClickPos != NULL) {
727 distanceFromClick = resourceClickPos->dist(resPos);
728 }
729 if(unit != NULL) {
730 distanceFromUnit = unit->getCenteredPos().dist(resPos);
731 }
732
733 *resourceClickPos = resPos;
734
735 if(unit == NULL || unit->isBadHarvestPos(*resourceClickPos) == false) {
736 //resourceNear = true;
737
738 //printf("%%----------- unit [%s - %d] resPos = [%s] resourceClickPos->dist(resPos) [%f] distanceFromClick [%f] unit->getCenteredPos().dist(resPos) [%f] distanceFromUnit [%f]\n",unit->getFullName().c_str(),unit->getId(),resPos.getString().c_str(),resourceClickPos->dist(resPos),distanceFromClick,unit->getCenteredPos().dist(resPos),distanceFromUnit);
739 }
740 }
741 }
742 }
743 }
744 }
745 }
746 }
747
748 float bestUnitDist = distanceFromUnit;
749 for(unsigned int i = 0; i < bestPosList.size(); ++i) {
750 FindBestPos &bestPosItem = bestPosList[i];
751
752 if(bestPosItem.distanceFromUnitNoAdjustment < bestUnitDist) {
753 bestUnitDist = bestPosItem.distanceFromUnitNoAdjustment;
754 *resourceClickPos = bestPosItem.resourcePosNoAdjustment;
755
756 if(unit == NULL || unit->isBadHarvestPos(*resourceClickPos) == false) {
757 //printf("%%----------- unit [%s - %d] resourceClickPos [%s] bestUnitDist [%f]\n",unit->getFullName().c_str(),unit->getId(),resourceClickPos->getString().c_str(),bestUnitDist);
758 }
759 }
760 }
761 }
762
763 return resourceNear;
764 }
765
766 // ==================== free cells ====================
767
isFreeCell(const Vec2i & pos,Field field) const768 bool Map::isFreeCell(const Vec2i &pos, Field field) const {
769 return
770 isInside(pos) &&
771 isInsideSurface(toSurfCoords(pos)) &&
772 getCell(pos)->isFree(field) &&
773 (field==fAir || getSurfaceCell(toSurfCoords(pos))->isFree()) &&
774 (field!=fLand || getDeepSubmerged(getCell(pos)) == false);
775 }
776
777
isFreeCellOrHasUnit(const Vec2i & pos,Field field,const Unit * unit) const778 bool Map::isFreeCellOrHasUnit(const Vec2i &pos, Field field, const Unit *unit) const{
779 if(isInside(pos)){
780 Cell *c= getCell(pos);
781 if(c->getUnit(field) == unit && unit != NULL) {
782 return true;
783 }
784 else{
785 return isFreeCell(pos, field);
786 }
787 }
788 return false;
789 }
790
791 //TT: this is much more complicated compared with the old one above. I think its no more needed
792 //bool Map::isFreeCellOrHasUnit(const Vec2i &pos, Field field, const Unit *unit) const {
793 // if(isInside(pos) && isInsideSurface(toSurfCoords(pos))) {
794 // if(unit->getCurrField() != field) {
795 // return isFreeCell(pos, field);
796 // }
797 // Cell *c= getCell(pos);
798 // if(c->getUnit(unit->getCurrField()) == unit) {
799 // if(unit->getCurrField() == fAir) {
800 // if(field == fAir) {
801 // return true;
802 // }
803 // const SurfaceCell *sc= getSurfaceCell(toSurfCoords(pos));
804 // if(sc != NULL) {
805 // if(getDeepSubmerged(sc) == true) {
806 // return false;
807 // }
808 // else if(field == fLand) {
809 // if(sc->isFree() == false) {
810 // return false;
811 // }
812 // else if(c->getUnit(field) != NULL) {
813 // return false;
814 // }
815 // }
816 // }
817 // }
818 // return true;
819 // }
820 // else{
821 // return isFreeCell(pos, field);
822 // }
823 // }
824 // return false;
825 //}
826
isAproxFreeCell(const Vec2i & pos,Field field,int teamIndex) const827 bool Map::isAproxFreeCell(const Vec2i &pos, Field field, int teamIndex) const {
828 if(isInside(pos) && isInsideSurface(toSurfCoords(pos))) {
829 const SurfaceCell *sc= getSurfaceCell(toSurfCoords(pos));
830
831 if(sc->isVisible(teamIndex)) {
832 return isFreeCell(pos, field);
833 }
834 else if(sc->isExplored(teamIndex)) {
835 return field==fLand? sc->isFree() && !getDeepSubmerged(getCell(pos)): true;
836 }
837 else {
838 return true;
839 }
840 }
841
842 //printf("[%s] Line: %d returning false\n",__FUNCTION__,__LINE__);
843 return false;
844 }
845
isFreeCells(const Vec2i & pos,int size,Field field) const846 bool Map::isFreeCells(const Vec2i & pos, int size, Field field) const {
847 for(int i=pos.x; i<pos.x+size; ++i) {
848 for(int j=pos.y; j<pos.y+size; ++j) {
849 Vec2i testPos(i,j);
850 if(isFreeCell(testPos, field) == false) {
851 return false;
852 }
853 }
854 }
855 return true;
856 }
857
isFreeCellsOrHasUnit(const Vec2i & pos,int size,Field field,const Unit * unit) const858 bool Map::isFreeCellsOrHasUnit(const Vec2i &pos, int size, Field field,
859 const Unit *unit) const {
860 for(int i = pos.x; i < pos.x + size; ++i) {
861 for(int j = pos.y; j < pos.y + size; ++j) {
862 if(isFreeCellOrHasUnit(Vec2i(i,j), field, unit) == false) {
863 return false;
864 }
865 }
866 }
867 return true;
868 }
869
isAproxFreeCells(const Vec2i & pos,int size,Field field,int teamIndex) const870 bool Map::isAproxFreeCells(const Vec2i &pos, int size, Field field, int teamIndex) const {
871 for(int i=pos.x; i<pos.x+size; ++i) {
872 for(int j=pos.y; j<pos.y+size; ++j) {
873 if(isAproxFreeCell(Vec2i(i, j), field, teamIndex) == false) {
874 return false;
875 }
876 }
877 }
878 return true;
879 }
880
canMorph(const Vec2i & pos,const Unit * currentUnit,const UnitType * targetUnitType) const881 bool Map::canMorph(const Vec2i &pos,const Unit *currentUnit,const UnitType *targetUnitType ) const{
882 Field field=targetUnitType->getField();
883 const UnitType *ut=targetUnitType;
884 CardinalDir facing=currentUnit->getModelFacing();
885
886 if (ut->hasCellMap() && isInside(pos) && isInsideSurface(toSurfCoords(pos))) {
887 for (int y=0; y < ut->getSize(); ++y) {
888 for (int x=0; x < ut->getSize(); ++x) {
889 Vec2i cellPos = pos + Vec2i(x, y);
890 if(isInside(cellPos) && isInsideSurface(toSurfCoords(cellPos))) {
891 if (ut->getCellMapCell(x, y, facing)) {
892 if (isFreeCellOrHasUnit(cellPos, field, currentUnit) == false) {
893 return false;
894 }
895 }
896 }
897 else {
898 return false;
899 }
900 }
901 }
902 return true;
903 }
904 else {
905 return isFreeCellsOrHasUnit(pos, ut->getSize(), field,currentUnit);
906 }
907 }
908
canOccupy(const Vec2i & pos,Field field,const UnitType * ut,CardinalDir facing)909 bool Map::canOccupy(const Vec2i &pos, Field field, const UnitType *ut, CardinalDir facing) {
910 if (ut->hasCellMap() && isInside(pos) && isInsideSurface(toSurfCoords(pos))) {
911 for (int y=0; y < ut->getSize(); ++y) {
912 for (int x=0; x < ut->getSize(); ++x) {
913 Vec2i cellPos = pos + Vec2i(x, y);
914 if(isInside(cellPos) && isInsideSurface(toSurfCoords(cellPos))) {
915 if (ut->getCellMapCell(x, y, facing)) {
916 if (isFreeCell(cellPos, field) == false) {
917 return false;
918 }
919 }
920 }
921 else {
922 return false;
923 }
924 }
925 }
926 return true;
927 }
928 else {
929 return isFreeCells(pos, ut->getSize(), field);
930 }
931 }
932
933 // ==================== unit placement ====================
934
935 //checks if a unit can move from between 2 cells
canMove(const Unit * unit,const Vec2i & pos1,const Vec2i & pos2,std::map<Vec2i,std::map<Vec2i,std::map<int,std::map<Field,bool>>>> * lookupCache) const936 bool Map::canMove(const Unit *unit, const Vec2i &pos1, const Vec2i &pos2, std::map<Vec2i, std::map<Vec2i, std::map<int, std::map<Field,bool> > > > *lookupCache) const {
937 int size= unit->getType()->getSize();
938 Field field= unit->getCurrField();
939
940 if(lookupCache != NULL) {
941 std::map<Vec2i, std::map<Vec2i, std::map<int, std::map<Field,bool> > > >::const_iterator iterFind1 = lookupCache->find(pos1);
942 if(iterFind1 != lookupCache->end()) {
943 std::map<Vec2i, std::map<int, std::map<Field,bool> > >::const_iterator iterFind2 = iterFind1->second.find(pos2);
944 if(iterFind2 != iterFind1->second.end()) {
945 std::map<int, std::map<Field,bool> >::const_iterator iterFind3 = iterFind2->second.find(size);
946 if(iterFind3 != iterFind2->second.end()) {
947 std::map<Field,bool>::const_iterator iterFind4 = iterFind3->second.find(field);
948 if(iterFind4 != iterFind3->second.end()) {
949 // Found this result in the cache
950 return iterFind4->second;
951 }
952 }
953 }
954 }
955 }
956
957 for(int i=pos2.x; i<pos2.x+size; ++i) {
958 for(int j=pos2.y; j<pos2.y+size; ++j) {
959 if(isInside(i, j) && isInsideSurface(toSurfCoords(Vec2i(i,j)))) {
960 if(getCell(i, j)->getUnit(field) != unit) {
961 if(isFreeCell(Vec2i(i, j), field) == false) {
962 if(lookupCache != NULL) {
963 (*lookupCache)[pos1][pos2][size][field]=false;
964 }
965
966 return false;
967 }
968 }
969 }
970 else {
971 if(lookupCache != NULL) {
972 (*lookupCache)[pos1][pos2][size][field]=false;
973 }
974
975 return false;
976 }
977 }
978 }
979
980 bool isBadHarvestPos = false;
981 //if(unit != NULL) {
982 Command *command= unit->getCurrCommand();
983 if(command != NULL) {
984 const HarvestCommandType *hct = dynamic_cast<const HarvestCommandType*>(command->getCommandType());
985 if(hct != NULL && unit->isBadHarvestPos(pos2) == true) {
986 isBadHarvestPos = true;
987 }
988 }
989 //}
990
991 if(isBadHarvestPos == true) {
992 if(lookupCache != NULL) {
993 (*lookupCache)[pos1][pos2][size][field]=false;
994 }
995
996 return false;
997 }
998
999 if(lookupCache != NULL) {
1000 (*lookupCache)[pos1][pos2][size][field]=true;
1001 }
1002
1003 return true;
1004 }
1005
1006 //checks if a unit can move from between 2 cells using only visible cells (for pathfinding)
aproxCanMove(const Unit * unit,const Vec2i & pos1,const Vec2i & pos2,std::map<Vec2i,std::map<Vec2i,std::map<int,std::map<int,std::map<Field,bool>>>>> * lookupCache) const1007 bool Map::aproxCanMove(const Unit *unit, const Vec2i &pos1, const Vec2i &pos2, std::map<Vec2i, std::map<Vec2i, std::map<int, std::map<int, std::map<Field,bool> > > > > *lookupCache) const {
1008 if(isInside(pos1) == false || isInsideSurface(toSurfCoords(pos1)) == false ||
1009 isInside(pos2) == false || isInsideSurface(toSurfCoords(pos2)) == false) {
1010
1011 //printf("[%s] Line: %d returning false\n",__FUNCTION__,__LINE__);
1012 return false;
1013 }
1014
1015 if(unit == NULL) {
1016 throw megaglest_runtime_error("unit == NULL");
1017 }
1018 int size= unit->getType()->getSize();
1019 int teamIndex= unit->getTeam();
1020 Field field= unit->getCurrField();
1021
1022 if(lookupCache != NULL) {
1023 std::map<Vec2i, std::map<Vec2i, std::map<int, std::map<int, std::map<Field,bool> > > > >::const_iterator iterFind1 = lookupCache->find(pos1);
1024 if(iterFind1 != lookupCache->end()) {
1025 std::map<Vec2i, std::map<int, std::map<int, std::map<Field,bool> > > >::const_iterator iterFind2 = iterFind1->second.find(pos2);
1026 if(iterFind2 != iterFind1->second.end()) {
1027 std::map<int, std::map<int, std::map<Field,bool> > >::const_iterator iterFind3 = iterFind2->second.find(teamIndex);
1028 if(iterFind3 != iterFind2->second.end()) {
1029 std::map<int, std::map<Field,bool> >::const_iterator iterFind4 = iterFind3->second.find(size);
1030 if(iterFind4 != iterFind3->second.end()) {
1031 std::map<Field,bool>::const_iterator iterFind5 = iterFind4->second.find(field);
1032 if(iterFind5 != iterFind4->second.end()) {
1033 // Found this result in the cache
1034 if(iterFind5->second == false) {
1035 //printf("[%s] Line: %d returning false\n",__FUNCTION__,__LINE__);
1036 }
1037 return iterFind5->second;
1038 }
1039 }
1040 }
1041 }
1042 }
1043 }
1044
1045 //single cell units
1046 if(size == 1) {
1047 if(isAproxFreeCell(pos2, field, teamIndex) == false) {
1048 if(lookupCache != NULL) {
1049 (*lookupCache)[pos1][pos2][teamIndex][size][field]=false;
1050 }
1051
1052 //printf("[%s] Line: %d returning false\n",__FUNCTION__,__LINE__);
1053 return false;
1054 }
1055 if(pos1.x != pos2.x && pos1.y != pos2.y) {
1056 if(isAproxFreeCell(Vec2i(pos1.x, pos2.y), field, teamIndex) == false) {
1057 if(lookupCache != NULL) {
1058 (*lookupCache)[pos1][pos2][teamIndex][size][field]=false;
1059 }
1060
1061 //Unit *cellUnit = getCell(Vec2i(pos1.x, pos2.y))->getUnit(field);
1062 //Object * obj = getSurfaceCell(toSurfCoords(Vec2i(pos1.x, pos2.y)))->getObject();
1063
1064 //printf("[%s] Line: %d returning false cell [%s] free [%d] cell unitid = %d object class = %d\n",__FUNCTION__,__LINE__,Vec2i(pos1.x, pos2.y).getString().c_str(),this->isFreeCell(Vec2i(pos1.x, pos2.y),field),(cellUnit != NULL ? cellUnit->getId() : -1),(obj != NULL ? obj->getType()->getClass() : -1));
1065 //printf("[%s] Line: %d returning false\n",__FUNCTION__,__LINE__);
1066 return false;
1067 }
1068 if(isAproxFreeCell(Vec2i(pos2.x, pos1.y), field, teamIndex) == false) {
1069 if(lookupCache != NULL) {
1070 (*lookupCache)[pos1][pos2][teamIndex][size][field]=false;
1071 }
1072
1073 //printf("[%s] Line: %d returning false\n",__FUNCTION__,__LINE__);
1074 return false;
1075 }
1076 }
1077
1078 bool isBadHarvestPos = false;
1079 //if(unit != NULL) {
1080 Command *command= unit->getCurrCommand();
1081 if(command != NULL) {
1082 const HarvestCommandType *hct = dynamic_cast<const HarvestCommandType*>(command->getCommandType());
1083 if(hct != NULL && unit->isBadHarvestPos(pos2) == true) {
1084 isBadHarvestPos = true;
1085 }
1086 }
1087 //}
1088
1089 if(unit == NULL || isBadHarvestPos == true) {
1090 if(lookupCache != NULL) {
1091 (*lookupCache)[pos1][pos2][teamIndex][size][field]=false;
1092 }
1093
1094 //printf("[%s] Line: %d returning false\n",__FUNCTION__,__LINE__);
1095 return false;
1096 }
1097
1098 if(lookupCache != NULL) {
1099 (*lookupCache)[pos1][pos2][teamIndex][size][field]=true;
1100 }
1101
1102 return true;
1103 }
1104 //multi cell units
1105 else {
1106 for(int i = pos2.x; i < pos2.x + size; ++i) {
1107 for(int j = pos2.y; j < pos2.y + size; ++j) {
1108
1109 Vec2i cellPos = Vec2i(i,j);
1110 if(isInside(cellPos) && isInsideSurface(toSurfCoords(cellPos))) {
1111 if(getCell(cellPos)->getUnit(unit->getCurrField()) != unit) {
1112 if(isAproxFreeCell(cellPos, field, teamIndex) == false) {
1113 if(lookupCache != NULL) {
1114 (*lookupCache)[pos1][pos2][teamIndex][size][field]=false;
1115 }
1116
1117 //printf("[%s] Line: %d returning false\n",__FUNCTION__,__LINE__);
1118 return false;
1119 }
1120 }
1121 }
1122 else {
1123
1124 if(lookupCache != NULL) {
1125 (*lookupCache)[pos1][pos2][teamIndex][size][field]=false;
1126 }
1127
1128 //printf("[%s] Line: %d returning false\n",__FUNCTION__,__LINE__);
1129 return false;
1130 }
1131 }
1132 }
1133
1134 bool isBadHarvestPos = false;
1135 Command *command= unit->getCurrCommand();
1136 if(command != NULL) {
1137 const HarvestCommandType *hct = dynamic_cast<const HarvestCommandType*>(command->getCommandType());
1138 if(hct != NULL && unit->isBadHarvestPos(pos2) == true) {
1139 isBadHarvestPos = true;
1140 }
1141 }
1142
1143 if(isBadHarvestPos == true) {
1144 if(lookupCache != NULL) {
1145 (*lookupCache)[pos1][pos2][teamIndex][size][field]=false;
1146 }
1147
1148 //printf("[%s] Line: %d returning false\n",__FUNCTION__,__LINE__);
1149 return false;
1150 }
1151
1152 if(lookupCache != NULL) {
1153 (*lookupCache)[pos1][pos2][teamIndex][size][field]=true;
1154 }
1155 }
1156 return true;
1157 }
1158
1159
computeRefPos(const Selection * selection) const1160 Vec2i Map::computeRefPos(const Selection *selection) const {
1161 Vec2i total= Vec2i(0);
1162
1163 if(selection == NULL) {
1164 throw megaglest_runtime_error("selection == NULL");
1165 }
1166
1167 for(int i = 0; i < selection->getCount(); ++i) {
1168 if(selection->getUnit(i) == NULL) {
1169 throw megaglest_runtime_error("selection == NULL || selection->getUnit(i) == NULL");
1170 }
1171 total = total + selection->getUnit(i)->getPosNotThreadSafe();
1172 }
1173
1174 return Vec2i(total.x / selection->getCount(), total.y / selection->getCount());
1175 }
1176
computeDestPos(const Vec2i & refUnitPos,const Vec2i & unitPos,const Vec2i & commandPos) const1177 Vec2i Map::computeDestPos( const Vec2i &refUnitPos, const Vec2i &unitPos,
1178 const Vec2i &commandPos) const {
1179 Vec2i pos;
1180 // no more random needed
1181 // Vec2i posDiff = unitPos - refUnitPos;
1182 //
1183 // if(abs(posDiff.x) >= 3){
1184 // posDiff.x = posDiff.x % 3;
1185 // }
1186 //
1187 // if(abs(posDiff.y) >= 3){
1188 // posDiff.y = posDiff.y % 3;
1189 // }
1190
1191 pos = commandPos; //+ posDiff;
1192 clampPos(pos);
1193 return pos;
1194 }
1195
getUnitDistanceToPos(const Unit * unit,Vec2i pos,const UnitType * ut)1196 std::pair<float,Vec2i> Map::getUnitDistanceToPos(const Unit *unit,Vec2i pos,const UnitType *ut) {
1197 if(unit == NULL) {
1198 throw megaglest_runtime_error("unit == NULL");
1199 }
1200
1201 std::pair<float,Vec2i> result(-1,Vec2i(0));
1202 //int unitId= unit->getId();
1203 Vec2i unitPos= computeDestPos(unit->getPosNotThreadSafe(), unit->getPosNotThreadSafe(), pos);
1204
1205 Vec2i start = pos - Vec2i(1);
1206 int unitTypeSize = 0;
1207 if(ut != NULL) {
1208 unitTypeSize = ut->getSize();
1209 }
1210 Vec2i end = pos + Vec2i(unitTypeSize);
1211
1212 for(int i = start.x; i <= end.x; ++i) {
1213 for(int j = start.y; j <= end.y; ++j){
1214 Vec2i testPos(i,j);
1215
1216 if(ut == NULL || isInUnitTypeCells(ut, pos,testPos) == false) {
1217 float distance = unitPos.dist(testPos);
1218 if(result.first < 0 || result.first > distance) {
1219 result.first = distance;
1220 result.second = testPos;
1221 }
1222 }
1223 }
1224 }
1225
1226 return result;
1227 }
1228
findClosestUnitToPos(const Selection * selection,Vec2i originalBuildPos,const UnitType * ut) const1229 const Unit * Map::findClosestUnitToPos(const Selection *selection, Vec2i originalBuildPos,
1230 const UnitType *ut) const {
1231 const Unit *closestUnit = NULL;
1232 Vec2i refPos = computeRefPos(selection);
1233
1234 Vec2i pos = originalBuildPos;
1235
1236 float bestRange = -1;
1237
1238 Vec2i start = pos - Vec2i(1);
1239 int unitTypeSize = 0;
1240 if(ut != NULL) {
1241 unitTypeSize = ut->getSize();
1242 }
1243 Vec2i end = pos + Vec2i(unitTypeSize);
1244
1245 for(int i = 0; i < selection->getCount(); ++i) {
1246 const Unit *unit = selection->getUnit(i);
1247 //int unitId= unit->getId();
1248 Vec2i unitBuilderPos= computeDestPos(refPos, unit->getPosNotThreadSafe(), pos);
1249
1250 for(int i = start.x; i <= end.x; ++i) {
1251 for(int j = start.y; j <= end.y; ++j){
1252 Vec2i testPos(i,j);
1253 if(isInUnitTypeCells(ut, originalBuildPos,testPos) == false) {
1254 float distance = unitBuilderPos.dist(testPos);
1255 if(bestRange < 0 || bestRange > distance) {
1256 bestRange = distance;
1257 pos = testPos;
1258 closestUnit = unit;
1259 }
1260 }
1261 }
1262 }
1263 }
1264
1265 return closestUnit;
1266 }
1267
findBestBuildApproach(const Unit * unit,Vec2i originalBuildPos,const UnitType * ut) const1268 Vec2i Map::findBestBuildApproach(const Unit *unit, Vec2i originalBuildPos,const UnitType *ut) const {
1269 if(unit == NULL) {
1270 throw megaglest_runtime_error("unit == NULL");
1271 }
1272 if(ut == NULL) {
1273 throw megaglest_runtime_error("ut == NULL");
1274 }
1275
1276 Vec2i unitBuilderPos = unit->getPosNotThreadSafe();
1277 Vec2i pos = originalBuildPos;
1278
1279 float bestRange = -1;
1280
1281 Vec2i start = pos - Vec2i(unit->getType()->getSize());
1282 Vec2i end = pos + Vec2i(ut->getSize());
1283
1284 for(int i = start.x; i <= end.x; ++i) {
1285 for(int j = start.y; j <= end.y; ++j) {
1286 Vec2i testPos(i,j);
1287 if(isInUnitTypeCells(ut, originalBuildPos,testPos) == false) {
1288 float distance = unitBuilderPos.dist(testPos);
1289 if(bestRange < 0 || bestRange > distance) {
1290 // Check if the cell is occupied by another unit
1291 if(isFreeCellOrHasUnit(testPos, unit->getType()->getField(), unit) == true) {
1292 bestRange = distance;
1293 pos = testPos;
1294 }
1295 }
1296 }
1297 }
1298 }
1299
1300 return pos;
1301 }
1302
isNextToUnitTypeCells(const UnitType * ut,const Vec2i & pos,const Vec2i & testPos) const1303 bool Map::isNextToUnitTypeCells(const UnitType *ut, const Vec2i &pos,
1304 const Vec2i &testPos) const {
1305 bool isInsideDestUnitCells = isInUnitTypeCells(ut, pos,testPos);
1306 if(isInsideDestUnitCells == false) {
1307 //Cell *testCell = getCell(testPos);
1308 for(int i=-1; i <= ut->getSize(); ++i){
1309 for(int j = -1; j <= ut->getSize(); ++j) {
1310 Vec2i currPos = pos + Vec2i(i, j);
1311 if(isInside(currPos) == true && isInsideSurface(toSurfCoords(currPos)) == true) {
1312 //Cell *unitCell = getCell(currPos);
1313 //if(unitCell == testCell) {
1314 if(isNextTo(testPos,currPos) == true) {
1315 return true;
1316 }
1317 }
1318 }
1319 }
1320 }
1321
1322 return false;
1323 }
1324
1325 // is testPos in the cells of unitType where unitType's position is pos
isInUnitTypeCells(const UnitType * ut,const Vec2i & pos,const Vec2i & testPos) const1326 bool Map::isInUnitTypeCells(const UnitType *ut, const Vec2i &pos,
1327 const Vec2i &testPos) const {
1328 assert(ut != NULL);
1329 if(ut == NULL) {
1330 throw megaglest_runtime_error("ut == NULL");
1331 }
1332
1333 if(isInside(testPos) && isInsideSurface(toSurfCoords(testPos))) {
1334 Cell *testCell = getCell(testPos);
1335 for(int i=0; i < ut->getSize(); ++i){
1336 for(int j = 0; j < ut->getSize(); ++j) {
1337 Vec2i currPos = pos + Vec2i(i, j);
1338 if(isInside(currPos) && isInsideSurface(toSurfCoords(currPos))) {
1339 Cell *unitCell = getCell(currPos);
1340 if(unitCell == testCell) {
1341 return true;
1342 }
1343 }
1344 }
1345 }
1346 }
1347 return false;
1348 }
1349
1350 //put a units into the cells
putUnitCells(Unit * unit,const Vec2i & pos,bool ignoreSkill,bool threaded)1351 void Map::putUnitCells(Unit *unit, const Vec2i &pos, bool ignoreSkill, bool threaded) {
1352 assert(unit != NULL);
1353 if(unit == NULL) {
1354 throw megaglest_runtime_error("ut == NULL");
1355 }
1356 putUnitCellsPrivate(unit, pos, unit->getType(), false, threaded);
1357
1358 // block space for morphing units
1359 if(ignoreSkill==false &&
1360 unit->getCurrSkill() != NULL &&
1361 unit->getCurrSkill()->getClass() == scMorph) {
1362 Command *command= unit->getCurrCommand();
1363 if(command != NULL && command->getCommandType()->commandTypeClass == ccMorph){
1364 const MorphCommandType *mct= static_cast<const MorphCommandType*>(command->getCommandType());
1365 putUnitCellsPrivate(unit, pos, mct->getMorphUnit(),true, threaded);
1366 unit->setMorphFieldsBlocked(true);
1367 }
1368 }
1369 }
1370
putUnitCellsPrivate(Unit * unit,const Vec2i & pos,const UnitType * ut,bool isMorph,bool threaded)1371 void Map::putUnitCellsPrivate(Unit *unit, const Vec2i &pos, const UnitType *ut, bool isMorph, bool threaded) {
1372 assert(unit != NULL);
1373 if(unit == NULL) {
1374 throw megaglest_runtime_error("ut == NULL");
1375 }
1376
1377 bool canPutInCell = true;
1378 Field field=ut->getField();
1379 for(int i = 0; i < ut->getSize(); ++i) {
1380 for(int j = 0; j < ut->getSize(); ++j) {
1381 Vec2i currPos= pos + Vec2i(i, j);
1382 assert(isInside(currPos));
1383 if(isInside(currPos) == false) {
1384 throw megaglest_runtime_error("isInside(currPos) == false");
1385 }
1386
1387 if( ut->hasCellMap() == false || ut->getCellMapCell(i, j, unit->getModelFacing())) {
1388 if(getCell(currPos)->getUnit(field) != NULL &&
1389 getCell(currPos)->getUnit(field) != unit) {
1390
1391 // TT: is this ok ?
1392 // If unit tries to move into a cell where another unit resides
1393 // cancel the move command
1394 if(unit->getCurrSkill() != NULL &&
1395 unit->getCurrSkill()->getClass() == scMove) {
1396 canPutInCell = false;
1397 //unit->setCurrSkill(scStop);
1398 //unit->finishCommand();
1399
1400 //SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] POSSIBLE ERROR [getCell(currPos)->getUnit(unit->getCurrField()) != NULL] currPos [%s] unit [%s] cell unit [%s]\n",
1401 // __FILE__,__FUNCTION__,__LINE__,
1402 // currPos.getString().c_str(),
1403 // unit->toString().c_str(),
1404 // getCell(currPos)->getUnit(unit->getCurrField())->toString().c_str());
1405 }
1406 //TT: Nonsens?
1407 // else {
1408 // // If the unit trying to move into the cell is not in the moving state
1409 // // it is likely being created or morphed so we will will log the error
1410 // canPutInCell = false;
1411 // // throw megaglest_runtime_error("getCell(currPos)->getUnit(unit->getCurrField()) != NULL");
1412 // SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] ERROR [getCell(currPos)->getUnit(unit->getCurrField()) != NULL] currPos [%s] unit [%s] cell unit [%s]\n",
1413 // __FILE__,__FUNCTION__,__LINE__,
1414 // currPos.getString().c_str(),
1415 // unit->toString().c_str(),
1416 // getCell(currPos)->getUnit(unit->getCurrField())->toString().c_str());
1417 // }
1418 }
1419
1420
1421 if(getCell(currPos)->getUnit(field) == NULL ||
1422 getCell(currPos)->getUnit(field) == unit) {
1423 if(isMorph) {
1424 // unit is beeing morphed to another unit with maybe other field.
1425 getCell(currPos)->setUnit(field, unit);
1426 canPutInCell = false;
1427 }
1428 if(canPutInCell == true) {
1429 getCell(currPos)->setUnit(unit->getCurrField(), unit);
1430 }
1431 }
1432 else if(canPutInCell == true) {
1433 char szBuf[8096]="";
1434 snprintf(szBuf,8096,"Trying to move unit [%d - %s] into occupied cell [%s] and field = %d, unit already in cell [%d - %s] ",unit->getId(),unit->getType()->getName(false).c_str(),pos.getString().c_str(),field,getCell(currPos)->getUnit(field)->getId(),getCell(currPos)->getUnit(field)->getType()->getName(false).c_str());
1435 throw megaglest_runtime_error(szBuf);
1436 }
1437 }
1438 else if(ut->hasCellMap() == true &&
1439 ut->getAllowEmptyCellMap() == true &&
1440 ut->hasEmptyCellMap() == true) {
1441 getCell(currPos)->setUnitWithEmptyCellMap(unit->getCurrField(), unit);
1442
1443 //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] currPos = %s unit = %s\n",
1444 // __FILE__,__FUNCTION__,__LINE__,
1445 // currPos.getString().c_str(),
1446 // unit->toString().c_str());
1447 }
1448 }
1449 }
1450 if(canPutInCell == true) {
1451 unit->setPos(pos, false, threaded);
1452 }
1453 }
1454
1455 //removes a unit from cells
clearUnitCells(Unit * unit,const Vec2i & pos,bool ignoreSkill)1456 void Map::clearUnitCells(Unit *unit, const Vec2i &pos, bool ignoreSkill) {
1457 assert(unit != NULL);
1458 if(unit == NULL) {
1459 throw megaglest_runtime_error("unit == NULL");
1460 }
1461
1462 const UnitType *ut= unit->getType();
1463 Field currentField=unit->getCurrField();
1464
1465 if(ignoreSkill==false &&
1466 unit->getCurrSkill() != NULL &&
1467 unit->getCurrSkill()->getClass() == scMorph &&
1468 unit->getMorphFieldsBlocked() == true) {
1469 Command *command= unit->getCurrCommand();
1470 const MorphCommandType *mct= static_cast<const MorphCommandType*>(command->getCommandType());
1471 if(unit->getType()->getSize()<=mct->getMorphUnit()->getSize()){
1472 ut=mct->getMorphUnit();
1473 currentField=ut->getField();
1474 unit->setMorphFieldsBlocked(false);
1475 }
1476 }
1477
1478
1479 for(int i=0; i<ut->getSize(); ++i){
1480 for(int j=0; j<ut->getSize(); ++j){
1481 Vec2i currPos= pos + Vec2i(i, j);
1482 assert(isInside(currPos));
1483 if(isInside(currPos) == false) {
1484 throw megaglest_runtime_error("isInside(currPos) == false");
1485 }
1486
1487 if(ut->hasCellMap() == false || ut->getCellMapCell(i, j, unit->getModelFacing())) {
1488 // This seems to be a bad assert since you can clear the cell
1489 // for many reasons including a unit dieing.
1490
1491 //assert(getCell(currPos)->getUnit(unit->getCurrField()) == unit || getCell(currPos)->getUnit(unit->getCurrField()) == NULL);
1492 //if(getCell(currPos)->getUnit(unit->getCurrField()) != unit && getCell(currPos)->getUnit(unit->getCurrField()) != NULL) {
1493 // throw megaglest_runtime_error("getCell(currPos)->getUnit(unit->getCurrField()) != unit");
1494 //SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] ERROR [getCell(currPos)->getUnit(unit->getCurrField()) != unit] currPos [%s] unit [%s] cell unit [%s]\n",
1495 // __FILE__,__FUNCTION__,__LINE__,
1496 // currPos.getString().c_str(),
1497 // unit->toString().c_str(),
1498 // (getCell(currPos)->getUnit(unit->getCurrField()) != NULL ? getCell(currPos)->getUnit(unit->getCurrField())->toString().c_str() : "NULL"));
1499 //}
1500
1501 // Only clear the cell if its the unit we expect to clear out of it
1502 if(getCell(currPos)->getUnit(currentField) == unit) {
1503 getCell(currPos)->setUnit(currentField, NULL);
1504 }
1505 }
1506 else if(ut->hasCellMap() == true &&
1507 ut->getAllowEmptyCellMap() == true &&
1508 ut->hasEmptyCellMap() == true) {
1509 getCell(currPos)->setUnitWithEmptyCellMap(currentField, NULL);
1510
1511 //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] currPos = %s unit = %s\n",
1512 // __FILE__,__FUNCTION__,__LINE__,
1513 // currPos.getString().c_str(),
1514 // unit->toString().c_str());
1515 }
1516 }
1517 }
1518 }
1519
1520 // ==================== misc ====================
1521
1522 //return if unit is next to pos
isNextTo(const Vec2i & pos,const Unit * unit) const1523 bool Map::isNextTo(const Vec2i &pos, const Unit *unit) const {
1524
1525 for(int i=-1; i<=1; ++i) {
1526 for(int j=-1; j<=1; ++j) {
1527 if(isInside(pos.x+i, pos.y+j) && isInsideSurface(toSurfCoords(Vec2i(pos.x+i, pos.y+j)))) {
1528 if(getCell(pos.x+i, pos.y+j)->getUnit(fLand) == unit) {
1529 return true;
1530 }
1531 else if(getCell(pos.x+i, pos.y+j)->getUnitWithEmptyCellMap(fLand) == unit) {
1532 return true;
1533 }
1534 }
1535 }
1536 }
1537 return false;
1538 }
1539
1540 //return if unit is next to pos
isNextTo(const Unit * unit1,const Unit * unit2) const1541 bool Map::isNextTo(const Unit *unit1, const Unit *unit2) const {
1542 Vec2i pos = unit1->getPosNotThreadSafe();
1543 const UnitType *ut = unit1->getType();
1544 for (int y=-1; y < ut->getSize()+1; ++y) {
1545 for (int x=-1; x < ut->getSize()+1; ++x) {
1546 Vec2i cellPos = pos + Vec2i(x, y);
1547 if(isInside(cellPos) && isInsideSurface(toSurfCoords(cellPos))) {
1548 if(getCell(cellPos)->getUnit(fLand) == unit2) {
1549 return true;
1550 }
1551 else if(getCell(cellPos)->getUnitWithEmptyCellMap(fLand) == unit2) {
1552 return true;
1553 }
1554 }
1555 }
1556 }
1557
1558 return false;
1559 }
1560
1561 //return if unit is next to pos
isNextTo(const Vec2i & pos,const Vec2i & nextToPos) const1562 bool Map::isNextTo(const Vec2i &pos, const Vec2i &nextToPos) const {
1563
1564 for(int i=-1; i<=1; ++i) {
1565 for(int j=-1; j<=1; ++j) {
1566 if(isInside(pos.x+i, pos.y+j) && isInsideSurface(toSurfCoords(Vec2i(pos.x+i, pos.y+j)))) {
1567 if(getCell(pos.x+i, pos.y+j) == getCell(nextToPos.x,nextToPos.y)) {
1568 return true;
1569 }
1570 }
1571 }
1572 }
1573 return false;
1574 }
1575
clampPos(Vec2i & pos) const1576 void Map::clampPos(Vec2i &pos) const{
1577 if(pos.x<0){
1578 pos.x=0;
1579 }
1580 if(pos.y<0){
1581 pos.y=0;
1582 }
1583 if(pos.x>=w){
1584 pos.x=w-1;
1585 }
1586 if(pos.y>=h){
1587 pos.y=h-1;
1588 }
1589 }
1590
prepareTerrain(const Unit * unit)1591 void Map::prepareTerrain(const Unit *unit) {
1592 Chrono chrono;
1593 if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start();
1594
1595 flatternTerrain(unit);
1596
1597 if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
1598
1599 computeNormals();
1600
1601 if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
1602
1603 computeInterpolatedHeights();
1604
1605 if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
1606 }
1607
1608 // ==================== PRIVATE ====================
1609
1610 // ==================== compute ====================
1611
flatternTerrain(const Unit * unit)1612 void Map::flatternTerrain(const Unit *unit){
1613 float refHeight= getSurfaceCell(toSurfCoords(unit->getCenteredPos()))->getHeight();
1614 for(int i=-1; i<=unit->getType()->getSize(); ++i){
1615 for(int j=-1; j<=unit->getType()->getSize(); ++j){
1616 Vec2i pos= unit->getPosNotThreadSafe()+Vec2i(i, j);
1617 if(isInside(pos) && isInsideSurface(toSurfCoords(pos))) {
1618 Cell *c= getCell(pos);
1619 SurfaceCell *sc= getSurfaceCell(toSurfCoords(pos));
1620 //we change height if pos is inside world, if its free or ocupied by the currenty building
1621 if(sc->getObject() == NULL && (c->getUnit(fLand)==NULL || c->getUnit(fLand)==unit)) {
1622 sc->setHeight(refHeight,true);
1623 }
1624 }
1625 }
1626 }
1627 }
1628
1629 //compute normals
computeNormals()1630 void Map::computeNormals(){
1631 //compute center normals
1632 for(int i=1; i<surfaceW-1; ++i){
1633 for(int j=1; j<surfaceH-1; ++j){
1634 getSurfaceCell(i, j)->setNormal(
1635 getSurfaceCell(i, j)->getVertex().normal(getSurfaceCell(i, j-1)->getVertex(),
1636 getSurfaceCell(i+1, j)->getVertex(),
1637 getSurfaceCell(i, j+1)->getVertex(),
1638 getSurfaceCell(i-1, j)->getVertex()));
1639 }
1640 }
1641 }
1642
computeInterpolatedHeights()1643 void Map::computeInterpolatedHeights(){
1644
1645 for(int i=0; i<w; ++i){
1646 for(int j=0; j<h; ++j){
1647 getCell(i, j)->setHeight(getSurfaceCell(toSurfCoords(Vec2i(i, j)))->getHeight());
1648 }
1649 }
1650
1651 for(int i=1; i<surfaceW-1; ++i){
1652 for(int j=1; j<surfaceH-1; ++j){
1653 for(int k=0; k<cellScale; ++k){
1654 for(int l=0; l<cellScale; ++l){
1655 if(k==0 && l==0){
1656 getCell(i*cellScale, j*cellScale)->setHeight(getSurfaceCell(i, j)->getHeight());
1657 }
1658 else if(k!=0 && l==0){
1659 getCell(i*cellScale+k, j*cellScale)->setHeight((
1660 getSurfaceCell(i, j)->getHeight()+
1661 getSurfaceCell(i+1, j)->getHeight())/2.f);
1662 }
1663 else if(l!=0 && k==0){
1664 getCell(i*cellScale, j*cellScale+l)->setHeight((
1665 getSurfaceCell(i, j)->getHeight()+
1666 getSurfaceCell(i, j+1)->getHeight())/2.f);
1667 }
1668 else{
1669 getCell(i*cellScale+k, j*cellScale+l)->setHeight((
1670 getSurfaceCell(i, j)->getHeight()+
1671 getSurfaceCell(i, j+1)->getHeight()+
1672 getSurfaceCell(i+1, j)->getHeight()+
1673 getSurfaceCell(i+1, j+1)->getHeight())/4.f);
1674 }
1675 }
1676 }
1677 }
1678 }
1679 }
1680
smoothSurface(Tileset * tileset)1681 void Map::smoothSurface(Tileset *tileset) {
1682 float *oldHeights = new float[getSurfaceCellArraySize()];
1683 //int arraySize=getSurfaceCellArraySize();
1684
1685 for (int i = 0; i < getSurfaceCellArraySize(); ++i) {
1686 oldHeights[i] = surfaceCells[i].getHeight();
1687 }
1688
1689 for (int i = 1; i < surfaceW - 1; ++i) {
1690 for (int j = 1; j < surfaceH - 1; ++j) {
1691 float height = 0.f;
1692 float numUsedToSmooth = 0.f;
1693 for (int k = -1; k <= 1; ++k) {
1694 for (int l = -1; l <= 1; ++l) {
1695 #ifdef USE_STREFLOP
1696 if (cliffLevel<=0.1f || cliffLevel > streflop::fabs(static_cast<streflop::Simple>(oldHeights[(j) * surfaceW + (i)]
1697 - oldHeights[(j + k) * surfaceW + (i + l)]))) {
1698 #else
1699 if (cliffLevel<=0.1f || cliffLevel > fabs(oldHeights[(j) * surfaceW + (i)]
1700 - oldHeights[(j + k) * surfaceW + (i + l)])) {
1701 #endif
1702 height += oldHeights[(j + k) * surfaceW + (i + l)];
1703 numUsedToSmooth++;
1704 }
1705 else {
1706 // we have something which should not be smoothed!
1707 // This is a cliff and must be textured -> set cliff texture
1708 getSurfaceCell(i, j)->setSurfaceType(5);
1709 //set invisible blocking object and replace resource objects
1710 //and non blocking objects with invisible blocker too
1711 Object *formerObject =
1712 getSurfaceCell(i, j)->getObject();
1713 if (formerObject != NULL) {
1714 if (formerObject->getWalkable()
1715 || formerObject->getResource() != NULL) {
1716 delete formerObject;
1717 formerObject = NULL;
1718 }
1719 }
1720 if (formerObject == NULL) {
1721 Object *o = new Object(tileset->getObjectType(9),
1722 getSurfaceCell(i, j)->getVertex(),
1723 Vec2i(i,j));
1724 getSurfaceCell(i, j)->setObject(o);
1725 }
1726 }
1727 }
1728 }
1729
1730 height /= numUsedToSmooth;
1731 if(maxMapHeight<height){
1732 maxMapHeight=height;
1733 }
1734
1735 getSurfaceCell(i, j)->setHeight(height);
1736 Object *object = getSurfaceCell(i, j)->getObject();
1737 if (object != NULL) {
1738 object->setHeight(height);
1739 }
1740 }
1741 }
1742 delete[] oldHeights;
1743 }
1744
1745 void Map::computeNearSubmerged(){
1746
1747 for(int i=0; i<surfaceW-1; ++i){
1748 for(int j=0; j<surfaceH-1; ++j){
1749 bool anySubmerged= false;
1750 for(int k=-1; k<=2; ++k){
1751 for(int l=-1; l<=2; ++l){
1752 Vec2i pos= Vec2i(i+k, j+l);
1753 if(isInsideSurface(pos) && isInsideSurface(toSurfCoords(pos))) {
1754 if(getSubmerged(getSurfaceCell(pos)))
1755 anySubmerged= true;
1756 }
1757 }
1758 }
1759 getSurfaceCell(i, j)->setNearSubmerged(anySubmerged);
1760 }
1761 }
1762 }
1763
1764 void Map::computeCellColors(){
1765 for(int i=0; i<surfaceW; ++i){
1766 for(int j=0; j<surfaceH; ++j){
1767 SurfaceCell *sc= getSurfaceCell(i, j);
1768 if(getDeepSubmerged(sc)){
1769 float factor= clamp(waterLevel-sc->getHeight()*1.5f, 1.f, 1.5f);
1770 sc->setColor(Vec3f(1.0f, 1.0f, 1.0f)/factor);
1771 }
1772 else{
1773 sc->setColor(Vec3f(1.0f, 1.0f, 1.0f));
1774 }
1775 }
1776 }
1777 }
1778
1779 void Map::saveGame(XmlNode *rootNode) const {
1780 std::map<string,string> mapTagReplacements;
1781 XmlNode *mapNode = rootNode->addChild("Map");
1782
1783 // string title;
1784 mapNode->addAttribute("title",title, mapTagReplacements);
1785 // float waterLevel;
1786 mapNode->addAttribute("waterLevel",floatToStr(waterLevel,6), mapTagReplacements);
1787 // float heightFactor;
1788 mapNode->addAttribute("heightFactor",floatToStr(heightFactor,6), mapTagReplacements);
1789 // float cliffLevel;
1790 mapNode->addAttribute("cliffLevel",floatToStr(cliffLevel,6), mapTagReplacements);
1791 // int cameraHeight;
1792 mapNode->addAttribute("cameraHeight",intToStr(cameraHeight), mapTagReplacements);
1793 // int w;
1794 mapNode->addAttribute("w",intToStr(w), mapTagReplacements);
1795 // int h;
1796 mapNode->addAttribute("h",intToStr(h), mapTagReplacements);
1797 // int surfaceW;
1798 mapNode->addAttribute("surfaceW",intToStr(surfaceW), mapTagReplacements);
1799 // int surfaceH;
1800 mapNode->addAttribute("surfaceH",intToStr(surfaceH), mapTagReplacements);
1801 // int maxPlayers;
1802 mapNode->addAttribute("maxPlayers",intToStr(maxPlayers), mapTagReplacements);
1803 // Cell *cells;
1804 //printf("getCellArraySize() = %d\n",getCellArraySize());
1805 // for(unsigned int i = 0; i < getCellArraySize(); ++i) {
1806 // Cell &cell = cells[i];
1807 // cell.saveGame(mapNode,i);
1808 // }
1809 // SurfaceCell *surfaceCells;
1810 //printf("getSurfaceCellArraySize() = %d\n",getSurfaceCellArraySize());
1811
1812 string exploredList = "";
1813 string visibleList = "";
1814
1815 for(unsigned int i = 0; i < (unsigned int)getSurfaceCellArraySize(); ++i) {
1816 SurfaceCell &surfaceCell = surfaceCells[i];
1817
1818 if(exploredList != "") {
1819 exploredList += ",";
1820 }
1821
1822 for(unsigned int j = 0; j < (unsigned int)GameConstants::maxPlayers; ++j) {
1823 if(j > 0) {
1824 exploredList += "|";
1825 }
1826
1827 exploredList += intToStr(surfaceCell.isExplored(j));
1828 }
1829
1830 if(visibleList != "") {
1831 visibleList += ",";
1832 }
1833
1834 for(unsigned int j = 0; j < (unsigned int)GameConstants::maxPlayers; ++j) {
1835 if(j > 0) {
1836 visibleList += "|";
1837 }
1838
1839 visibleList += intToStr(surfaceCell.isVisible(j));
1840 }
1841
1842 surfaceCell.saveGame(mapNode,i);
1843
1844 if(i > 0 && i % 100 == 0) {
1845 XmlNode *surfaceCellNode = mapNode->addChild("SurfaceCell");
1846 surfaceCellNode->addAttribute("batchIndex",intToStr(i), mapTagReplacements);
1847 surfaceCellNode->addAttribute("exploredList",exploredList, mapTagReplacements);
1848 surfaceCellNode->addAttribute("visibleList",visibleList, mapTagReplacements);
1849
1850 exploredList = "";
1851 visibleList = "";
1852 }
1853 }
1854
1855 if(exploredList != "") {
1856 XmlNode *surfaceCellNode = mapNode->addChild("SurfaceCell");
1857 surfaceCellNode->addAttribute("batchIndex",intToStr(getSurfaceCellArraySize()), mapTagReplacements);
1858 surfaceCellNode->addAttribute("exploredList",exploredList, mapTagReplacements);
1859 surfaceCellNode->addAttribute("visibleList",visibleList, mapTagReplacements);
1860 }
1861
1862 // Vec2i *startLocations;
1863 for(unsigned int i = 0; i < (unsigned int)maxPlayers; ++i) {
1864 XmlNode *startLocationsNode = mapNode->addChild("startLocations");
1865 startLocationsNode->addAttribute("location",startLocations[i].getString(), mapTagReplacements);
1866 }
1867 // Checksum checksumValue;
1868 // mapNode->addAttribute("checksumValue",intToStr(checksumValue.getSum()), mapTagReplacements);
1869 // float maxMapHeight;
1870 mapNode->addAttribute("maxMapHeight",floatToStr(maxMapHeight,6), mapTagReplacements);
1871 // string mapFile;
1872 mapNode->addAttribute("mapFile",mapFile, mapTagReplacements);
1873 }
1874
1875 void Map::loadGame(const XmlNode *rootNode, World *world) {
1876 const XmlNode *mapNode = rootNode->getChild("Map");
1877
1878 //description = gameSettingsNode->getAttribute("description")->getValue();
1879
1880 // for(unsigned int i = 0; i < getCellArraySize(); ++i) {
1881 // Cell &cell = cells[i];
1882 // cell.saveGame(mapNode,i);
1883 // }
1884 // for(unsigned int i = 0; i < getSurfaceCellArraySize(); ++i) {
1885 // SurfaceCell &surfaceCell = surfaceCells[i];
1886 // surfaceCell.saveGame(mapNode,i);
1887 // }
1888
1889 // printf("getCellArraySize() = %d\n",getCellArraySize());
1890 // for(unsigned int i = 0; i < getCellArraySize(); ++i) {
1891 // Cell &cell = cells[i];
1892 // cell.loadGame(mapNode,i,world);
1893 // }
1894
1895 // printf("getSurfaceCellArraySize() = %d\n",getSurfaceCellArraySize());
1896 for(unsigned int i = 0; i < (unsigned int)getSurfaceCellArraySize(); ++i) {
1897 SurfaceCell &surfaceCell = surfaceCells[i];
1898 surfaceCell.loadGame(mapNode,i,world);
1899 }
1900
1901 int surfaceCellIndexExplored = 0;
1902 int surfaceCellIndexVisible = 0;
1903 vector<XmlNode *> surfaceCellNodeList = mapNode->getChildList("SurfaceCell");
1904 for(unsigned int i = 0; i < surfaceCellNodeList.size(); ++i) {
1905 XmlNode *surfaceCellNode = surfaceCellNodeList[i];
1906
1907 //XmlNode *surfaceCellNode = mapNode->getChild("SurfaceCell");
1908 string exploredList = surfaceCellNode->getAttribute("exploredList")->getValue();
1909 string visibleList = surfaceCellNode->getAttribute("visibleList")->getValue();
1910 //int batchIndex = surfaceCellNode->getAttribute("batchIndex")->getIntValue();
1911
1912 vector<string> tokensExplored;
1913 Tokenize(exploredList,tokensExplored,",");
1914
1915 //printf("=====================\nNew batchIndex = %d batchsize = %d\n",batchIndex,tokensExplored.size());
1916 //for(unsigned int j = 0; j < tokensExplored.size(); ++j) {
1917 //string valueList = tokensExplored[j];
1918 //printf("valueList [%s]\n",valueList.c_str());
1919 //}
1920 for(unsigned int j = 0; j < tokensExplored.size(); ++j) {
1921 string valueList = tokensExplored[j];
1922
1923 //int surfaceCellIndex = (i * tokensExplored.size()) + j;
1924 //printf("Loading sc = %d batchIndex = %d\n",surfaceCellIndexExplored,batchIndex);
1925 SurfaceCell &surfaceCell = surfaceCells[surfaceCellIndexExplored];
1926
1927 vector<string> tokensExploredValue;
1928 Tokenize(valueList,tokensExploredValue,"|");
1929
1930 // if(tokensExploredValue.size() != GameConstants::maxPlayers) {
1931 // for(unsigned int k = 0; k < tokensExploredValue.size(); ++k) {
1932 // string value = tokensExploredValue[k];
1933 // printf("k = %d [%s]\n",k,value.c_str());
1934 // }
1935 // throw megaglest_runtime_error("tokensExploredValue.size() [" + intToStr(tokensExploredValue.size()) + "] != GameConstants::maxPlayers");
1936 // }
1937 for(unsigned int k = 0; k < tokensExploredValue.size(); ++k) {
1938 string value = tokensExploredValue[k];
1939
1940 surfaceCell.setExplored(k,strToInt(value) != 0);
1941
1942 //if(surfaceCell.isExplored(k) == true) {
1943 // printf("Setting cell at index: %d for team: %d to: %d [%s]\n",surfaceCellIndexExplored,k,surfaceCell.isExplored(k),value.c_str());
1944 //}
1945 }
1946 surfaceCellIndexExplored++;
1947 }
1948
1949 vector<string> tokensVisible;
1950 Tokenize(visibleList,tokensVisible,",");
1951 for(unsigned int j = 0; j < tokensVisible.size(); ++j) {
1952 string valueList = tokensVisible[j];
1953
1954 //int surfaceCellIndex = (i * tokensVisible.size()) + j;
1955 SurfaceCell &surfaceCell = surfaceCells[surfaceCellIndexVisible];
1956
1957 vector<string> tokensVisibleValue;
1958 Tokenize(valueList,tokensVisibleValue,"|");
1959
1960 // if(tokensVisibleValue.size() != GameConstants::maxPlayers) {
1961 // throw megaglest_runtime_error("tokensVisibleValue.size() [" + intToStr(tokensVisibleValue.size()) + "] != GameConstants::maxPlayers");
1962 // }
1963
1964 for(unsigned int k = 0; k < tokensVisibleValue.size(); ++k) {
1965 string value = tokensVisibleValue[k];
1966
1967 surfaceCell.setVisible(k,strToInt(value) != 0);
1968 }
1969 surfaceCellIndexVisible++;
1970 }
1971 }
1972
1973 computeNormals();
1974 computeInterpolatedHeights();
1975 }
1976
1977 // =====================================================
1978 // class PosCircularIterator
1979 // =====================================================
1980
1981 PosCircularIterator::PosCircularIterator(const Map *map, const Vec2i ¢er, int radius){
1982 this->map= map;
1983 this->radius= radius;
1984 this->center= center;
1985 pos= center - Vec2i(radius, radius);
1986 pos.x-= 1;
1987 }
1988
1989 bool PosCircularIterator::next(){
1990
1991 //iterate while dont find a cell that is inside the world
1992 //and at less or equal distance that the radius
1993 do{
1994 pos.x++;
1995 if(pos.x > center.x+radius){
1996 pos.x= center.x-radius;
1997 pos.y++;
1998 }
1999 if(pos.y>center.y+radius)
2000 return false;
2001 }
2002 #ifdef USE_STREFLOP
2003 while(streflop::floor(static_cast<streflop::Simple>(pos.dist(center))) >= (radius+1) || !map->isInside(pos) || !map->isInsideSurface(map->toSurfCoords(pos)) );
2004 #else
2005 while(floor(pos.dist(center)) >= (radius+1) || !map->isInside(pos) || !map->isInsideSurface(map->toSurfCoords(pos)) );
2006 #endif
2007
2008 return true;
2009 }
2010
2011 const Vec2i &PosCircularIterator::getPos(){
2012 return pos;
2013 }
2014
2015
2016 // =====================================================
2017 // class PosQuadIterator
2018 // =====================================================
2019
2020 PosQuadIterator::PosQuadIterator(const Map *map,const Quad2i &quad, int step) {
2021 this->map = map;
2022
2023 this->quad= quad;
2024 this->boundingRect= quad.computeBoundingRect();
2025 this->step= step;
2026 pos= boundingRect.p[0];
2027 --pos.x;
2028 pos.x= (pos.x/step)*step;
2029 pos.y= (pos.y/step)*step;
2030 //map->clampPos(pos);
2031 }
2032
2033 bool PosQuadIterator::next() {
2034
2035 do {
2036 pos.x += step;
2037 if(pos.x > boundingRect.p[1].x) {
2038 pos.x = (boundingRect.p[0].x / step) * step;
2039 pos.y += step;
2040 }
2041 if(pos.y > boundingRect.p[1].y) {
2042 return false;
2043 }
2044
2045 //printf("pos [%s] boundingRect.p[0] [%s] boundingRect.p[1] [%s]\n",pos.getString().c_str(),boundingRect.p[0].getString().c_str(),boundingRect.p[1].getString().c_str());
2046 }
2047 while(!quad.isInside(pos));
2048
2049 return true;
2050 }
2051
2052 void PosQuadIterator::skipX() {
2053 pos.x+= step;
2054 }
2055
2056 const Vec2i &PosQuadIterator::getPos(){
2057 return pos;
2058 }
2059
2060 }}//end namespace
2061