alot of work with Alien Mod port; also, fixed state messup (ethereal state)
[k8-i-v-a-n.git] / src / game / worldmap.cpp
blob684ec144d6e40449bd272b49c3f73b85c76c43c2
1 /*
3 * Iter Vehemens ad Necem (IVAN)
4 * Copyright (C) Timo Kiviluoto
5 * Released under the GNU General
6 * Public License
8 * See LICENSING which should be included
9 * along with this file for more details
13 /* Compiled through wmapset.cpp */
15 #define MAX_TEMPERATURE 27 //increase for a warmer world
16 #define LATITUDE_EFFECT 40 //increase for more effect
17 #define ALTITUDE_EFFECT 0.02
19 #define COLD 10
20 #define MEDIUM 12
21 #define WARM 17
22 #define HOT 19
24 static const int DirX[8] = { -1, -1, -1, 0, 0, 1, 1, 1 };
25 static const int DirY[8] = { -1, 0, 1, -1, 1, -1, 0, 1 };
28 std::vector<owterrain *> worldmap::Places;
29 std::vector<int> worldmap::PlaceTypes;
30 std::vector<int> worldmap::PlaceDungeons;
31 std::vector<PlaceSpawner> worldmap::PlaceSpawners;
33 worldmap::worldmap () {}
34 continent *worldmap::GetContinentUnder (v2 Pos) const { return Continent[ContinentBuffer[Pos.X][Pos.Y]]; }
35 v2 worldmap::GetEntryPos (ccharacter *, int I) const { return EntryMap.find(I)->second; }
36 continent *worldmap::GetContinent (int I) const { return Continent[I]; }
37 int worldmap::GetAltitude (v2 Pos) { return AltitudeBuffer[Pos.X][Pos.Y]; }
38 charactervector &worldmap::GetPlayerGroup () { return PlayerGroup; }
39 character *worldmap::GetPlayerGroupMember (int c) { return PlayerGroup[c]; }
42 worldmap::worldmap (int XSize, int YSize) : area(XSize, YSize) {
43 Map = reinterpret_cast<wsquare ***>(area::Map);
44 for (int x = 0; x < XSize; ++x) {
45 for (int y = 0; y < YSize; ++y) {
46 Map[x][y] = new wsquare(this, v2(x, y));
47 Map[x][y]->SetGWTerrain(ocean::Spawn());
50 Alloc2D(TypeBuffer, XSize, YSize);
51 Alloc2D(AltitudeBuffer, XSize, YSize);
52 Alloc2D(ContinentBuffer, XSize, YSize);
53 continent::TypeBuffer = TypeBuffer;
54 continent::AltitudeBuffer = AltitudeBuffer;
55 continent::ContinentBuffer = ContinentBuffer;
59 worldmap::~worldmap () {
60 delete [] TypeBuffer;
61 delete [] AltitudeBuffer;
62 delete [] ContinentBuffer;
63 for (uInt c = 1; c < Continent.size(); ++c) delete Continent[c];
64 for (uInt c = 0; c < PlayerGroup.size(); ++c) delete PlayerGroup[c];
68 void worldmap::Save (outputfile &SaveFile) const {
69 area::Save(SaveFile);
70 SaveFile.Write(reinterpret_cast<char*>(TypeBuffer[0]), XSizeTimesYSize*sizeof(uChar));
71 SaveFile.Write(reinterpret_cast<char*>(AltitudeBuffer[0]), XSizeTimesYSize*sizeof(short));
72 SaveFile.Write(reinterpret_cast<char*>(ContinentBuffer[0]), XSizeTimesYSize*sizeof(uChar));
73 for (feuLong c = 0; c < XSizeTimesYSize; ++c) Map[0][c]->Save(SaveFile);
74 SaveFile << Continent << PlayerGroup;
78 void worldmap::Load (inputfile &SaveFile) {
79 area::Load(SaveFile);
80 Map = reinterpret_cast<wsquare ***>(area::Map);
81 Alloc2D(TypeBuffer, XSize, YSize);
82 Alloc2D(AltitudeBuffer, XSize, YSize);
83 Alloc2D(ContinentBuffer, XSize, YSize);
84 SaveFile.Read(reinterpret_cast<char*>(TypeBuffer[0]), XSizeTimesYSize*sizeof(uChar));
85 SaveFile.Read(reinterpret_cast<char*>(AltitudeBuffer[0]), XSizeTimesYSize*sizeof(short));
86 SaveFile.Read(reinterpret_cast<char*>(ContinentBuffer[0]), XSizeTimesYSize*sizeof(uChar));
87 continent::TypeBuffer = TypeBuffer;
88 continent::AltitudeBuffer = AltitudeBuffer;
89 continent::ContinentBuffer = ContinentBuffer;
90 int x, y;
91 for (x = 0; x < XSize; ++x)
92 for (y = 0; y < YSize; ++y)
93 Map[x][y] = new wsquare(this, v2(x, y));
94 for (x = 0; x < XSize; ++x) {
95 for (y = 0; y < YSize; ++y) {
96 game::SetSquareInLoad(Map[x][y]);
97 Map[x][y]->Load(SaveFile);
100 CalculateNeighbourBitmapPoses();
101 SaveFile >> Continent >> PlayerGroup;
105 void worldmap::Generate () {
106 Alloc2D(OldAltitudeBuffer, XSize, YSize);
107 Alloc2D(OldTypeBuffer, XSize, YSize);
109 //fprintf(stderr, "places: %u\n", Places.size());
110 for (;;) {
111 allagain:
112 PlacePosition.clear();
113 PlaceRevealed.clear();
114 PlaceContinent.clear();
115 for (unsigned int f = 0; f < Places.size(); ++f) {
116 PlacePosition.push_back(ERROR_V2);
117 PlaceRevealed.push_back(false);
118 PlaceContinent.push_back(0);
121 RandomizeAltitude();
122 SmoothAltitude();
123 GenerateClimate();
124 SmoothClimate();
125 CalculateContinents();
127 std::vector<continent *> PerfectForAttnam, PerfectForNewAttnam;
128 continent *PetrusLikes = 0;
129 int nearPetrusCount = 0;
131 // find places for attnam
132 for (unsigned int f = 0; f < Places.size(); ++f) {
133 if (Places[f]->IsAttnam()) {
134 for (uInt c = 1; c < Continent.size(); ++c) {
135 if (Places[f]->IsSuitableContinent(Continent[c])) PerfectForAttnam.push_back(Continent[c]);
137 } else if (Places[f]->WantPetrusContinent()) {
138 ++nearPetrusCount;
141 if (!PerfectForAttnam.size()) continue;
142 // try to place all 'near petrus' places
143 while (PerfectForAttnam.size() > 0) {
144 int pno = RAND()%PerfectForAttnam.size();
145 int nphit = 0;
147 PetrusLikes = PerfectForAttnam[pno];
148 for (unsigned int f = 0; f < Places.size(); ++f) {
149 if (!Places[f]->IsAttnam() && Places[f]->WantPetrusContinent() && Places[f]->IsSuitableContinent(PetrusLikes)) {
150 ++nphit;
153 if (nphit == nearPetrusCount) break; // ok
154 // try again
155 PetrusLikes = 0;
157 if (!PetrusLikes) continue; // alas
158 //TODO: try non-petrus-wants
160 v2 NewAttnamPos, TunnelEntry, TunnelExit;
161 //v2 AttnamPos, ElpuriCavePos, NewAttnamPos, TunnelEntry, TunnelExit, MondedrPos, MuntuoPos;
162 //v2 DragonTowerPos, DarkForestPos, XinrochTombPos;
163 truth Correct = false;
164 for (unsigned int f = 0; f < Places.size(); ++f) {
165 if (Places[f]->IsAttnam() || Places[f]->WantPetrusContinent()) PlacePosition[f] = ERROR_V2;
168 for (int c1 = 0; c1 < 25; ++c1) {
169 game::BusyAnimation();
171 //PetrusLikes = PerfectForAttnam[RAND() % PerfectForAttnam.size()];
172 for (unsigned int f = 0; f < Places.size(); ++f) {
173 if (Places[f]->IsAttnam() || Places[f]->WantPetrusContinent()) {
174 truth success = false;
175 PlacePosition[f] = PetrusLikes->GetRandomMember(PlaceTypes[f], &success);
176 if (!success) goto allagain; //FIXME: memory leak
180 for (int c2 = 1; c2 < 50; ++c2) {
181 truth tunnelExitOkPos = true;
183 TunnelExit = PetrusLikes->GetMember(RAND()%PetrusLikes->GetSize());
184 for (unsigned int f = 0; f < Places.size(); ++f) {
185 if (PlacePosition[f] != ERROR_V2) {
186 if (PlacePosition[f] == TunnelExit) { tunnelExitOkPos = false; break; }
189 if (!tunnelExitOkPos) continue;
191 for (int d1 = 0; d1 < 8; ++d1) {
192 v2 Pos = TunnelExit+game::GetMoveVector(d1);
194 if (IsValidPos(Pos) && AltitudeBuffer[Pos.X][Pos.Y] <= 0) {
195 int Distance = 3+(RAND() & 3);
196 truth Error = false;
197 int x, y;
198 int Counter = 0;
200 TunnelEntry = Pos;
201 for (int c2 = 0; c2 < Distance; ++c2) {
202 TunnelEntry += game::GetMoveVector(d1);
203 if (!IsValidPos(TunnelEntry) || AltitudeBuffer[TunnelEntry.X][TunnelEntry.Y] > 0) { Error = true; break; }
205 if (Error) continue;
206 for (x = TunnelEntry.X-3; x <= TunnelEntry.X+3; ++x) {
207 for (y = TunnelEntry.Y-3; y <= TunnelEntry.Y+3; ++y, ++Counter) {
208 if (Counter != 0 && Counter != 6 && Counter != 42 && Counter != 48 &&
209 (!IsValidPos(x, y) || AltitudeBuffer[x][y] > 0 || AltitudeBuffer[x][y] < -350)) {
210 Error = true;
211 break;
214 if (Error) break;
216 if (Error) continue;
217 Error = true;
218 for (x = 0; x < XSize; ++x) if (TypeBuffer[x][TunnelEntry.Y] == JungleType) { Error = false; break; }
219 if (Error) continue;
220 Counter = 0;
221 for (x = TunnelEntry.X - 2; x <= TunnelEntry.X+2; ++x) {
222 for (y = TunnelEntry.Y - 2; y <= TunnelEntry.Y+2; ++y, ++Counter) {
223 if (Counter != 0 && Counter != 4 && Counter != 20 && Counter != 24) AltitudeBuffer[x][y] /= 2;
226 AltitudeBuffer[TunnelEntry.X][TunnelEntry.Y] = 1+RAND()%50;
227 TypeBuffer[TunnelEntry.X][TunnelEntry.Y] = JungleType;
228 GetWSquare(TunnelEntry)->ChangeGWTerrain(jungle::Spawn());
230 int NewAttnamIndex;
231 for (NewAttnamIndex = RAND()&7; NewAttnamIndex == 7-d1; NewAttnamIndex = RAND()&7) ;
232 NewAttnamPos = TunnelEntry+game::GetMoveVector(NewAttnamIndex);
234 static const int DiagonalDir[4] = { 0, 2, 5, 7 };
235 static const int NotDiagonalDir[4] = { 1, 3, 4, 6 };
236 static const int AdjacentDir[4][2] = { { 0, 1 }, { 0, 2 }, { 1, 3 }, { 2, 3 } };
237 truth Raised[] = { false, false, false, false };
239 for (int d2 = 0; d2 < 4; ++d2) {
240 if (NotDiagonalDir[d2] != 7-d1 && (NotDiagonalDir[d2] == NewAttnamIndex || !(RAND()&2))) {
241 v2 Pos = TunnelEntry+game::GetMoveVector(NotDiagonalDir[d2]);
242 AltitudeBuffer[Pos.X][Pos.Y] = 1+RAND()%50;
243 TypeBuffer[Pos.X][Pos.Y] = JungleType;
244 GetWSquare(Pos)->ChangeGWTerrain(jungle::Spawn());
245 Raised[d2] = true;
248 for (int d2 = 0; d2 < 4; ++d2) {
249 if (DiagonalDir[d2] != 7-d1 &&
250 (DiagonalDir[d2] == NewAttnamIndex ||
251 (Raised[AdjacentDir[d2][0]] && Raised[AdjacentDir[d2][1]] && !(RAND()&2)))) {
252 v2 Pos = TunnelEntry+game::GetMoveVector(DiagonalDir[d2]);
254 AltitudeBuffer[Pos.X][Pos.Y] = 1+RAND()%50;
255 TypeBuffer[Pos.X][Pos.Y] = JungleType;
256 GetWSquare(Pos)->ChangeGWTerrain(jungle::Spawn());
259 Correct = true;
260 break;
263 if (Correct) break;
265 if (Correct) break;
267 if (!Correct) continue;
269 // tunnel entry, tunnel exit and New Attnam are ok, spawn
270 for (unsigned int f = 0; f < Places.size(); ++f) {
271 switch (PlaceDungeons[f]) {
272 case NEW_ATTNAM:
273 GetWSquare(NewAttnamPos)->ChangeOWTerrain(PlaceSpawners[f]());
274 SetEntryPos(NEW_ATTNAM, NewAttnamPos);
275 PlacePosition[f] = NewAttnamPos;
276 break;
277 case UNDER_WATER_TUNNEL:
278 GetWSquare(TunnelEntry)->ChangeOWTerrain(PlaceSpawners[f]());
279 SetEntryPos(UNDER_WATER_TUNNEL, TunnelEntry);
280 PlacePosition[f] = TunnelEntry;
281 break;
282 case UNDER_WATER_TUNNEL_EXIT:
283 GetWSquare(TunnelExit)->ChangeOWTerrain(PlaceSpawners[f]());
284 SetEntryPos(UNDER_WATER_TUNNEL_EXIT, TunnelExit);
285 PlacePosition[f] = TunnelExit;
286 break;
289 // spawn others
290 for (unsigned int f = 0; f < Places.size(); ++f) {
291 if (!Places[f]->IsAttnam() && !Places[f]->WantPetrusContinent()) continue;
292 if (!Places[f]->IsHidden()) GetWSquare(PlacePosition[f])->ChangeOWTerrain(PlaceSpawners[f]());
293 SetEntryPos(PlaceDungeons[f], PlacePosition[f]);
294 if (Places[f]->IsRevealed()) RevealEnvironment(PlacePosition[f], 1);
297 PLAYER->PutTo(NewAttnamPos);
299 CalculateLuminances();
300 CalculateNeighbourBitmapPoses();
301 break;
303 delete [] OldAltitudeBuffer;
304 delete [] OldTypeBuffer;
308 void worldmap::RandomizeAltitude () {
309 game::BusyAnimation();
310 for (int x = 0; x < XSize; ++x)
311 for (int y = 0; y < YSize; ++y)
312 AltitudeBuffer[x][y] = 4000 - RAND() % 8000;
316 void worldmap::SmoothAltitude () {
317 for (int c = 0; c < 10; ++c) {
318 game::BusyAnimation();
319 int x, y;
320 for (y = 0; y < YSize; ++y) SafeSmooth(0, y);
321 for (x = 1; x < XSize - 1; ++x) {
322 SafeSmooth(x, 0);
323 for (y = 1; y < YSize - 1; ++y) FastSmooth(x, y);
324 SafeSmooth(x, YSize - 1);
326 for (y = 0; y < YSize; ++y) SafeSmooth(XSize - 1, y);
331 void worldmap::FastSmooth (int x, int y) {
332 sLong HeightNear = 0;
333 int d;
334 for (d = 0; d < 4; ++d) HeightNear += OldAltitudeBuffer[x + DirX[d]][y + DirY[d]];
335 for (d = 4; d < 8; ++d) HeightNear += AltitudeBuffer[x + DirX[d]][y + DirY[d]];
336 OldAltitudeBuffer[x][y] = AltitudeBuffer[x][y];
337 AltitudeBuffer[x][y] = HeightNear >> 3;
341 void worldmap::SafeSmooth (int x, int y) {
342 sLong HeightNear = 0;
343 int d, SquaresNear = 0;
344 for (d = 0; d < 4; ++d) {
345 int X = x + DirX[d];
346 int Y = y + DirY[d];
347 if (IsValidPos(X, Y)) {
348 HeightNear += OldAltitudeBuffer[X][Y];
349 ++SquaresNear;
352 for (d = 4; d < 8; ++d) {
353 int X = x + DirX[d];
354 int Y = y + DirY[d];
355 if (IsValidPos(X, Y)) {
356 HeightNear += AltitudeBuffer[X][Y];
357 ++SquaresNear;
360 OldAltitudeBuffer[x][y] = AltitudeBuffer[x][y];
361 AltitudeBuffer[x][y] = HeightNear / SquaresNear;
365 void worldmap::GenerateClimate () {
366 game::BusyAnimation();
367 for (int y = 0; y < YSize; ++y) {
368 double DistanceFromEquator = fabs(double(y) / YSize - 0.5);
369 truth LatitudeRainy = DistanceFromEquator <= 0.05 || (DistanceFromEquator > 0.25 && DistanceFromEquator <= 0.45);
370 for (int x = 0; x < XSize; ++x) {
371 if (AltitudeBuffer[x][y] <= 0) {
372 TypeBuffer[x][y] = OceanType;
373 continue;
375 truth Rainy = LatitudeRainy;
376 if (!Rainy) {
377 for(int d = 0; d < 8; ++d) {
378 v2 Pos = v2(x, y) + game::GetMoveVector(d);
379 if (IsValidPos(Pos) && AltitudeBuffer[Pos.X][Pos.Y] <= 0) {
380 Rainy = true;
381 break;
385 int Temperature = int(MAX_TEMPERATURE-DistanceFromEquator*LATITUDE_EFFECT-AltitudeBuffer[x][y]*ALTITUDE_EFFECT);
386 int Type = 0;
387 if (Temperature <= COLD) Type = Rainy ? SnowType : GlacierType;
388 else if (Temperature <= MEDIUM) Type = Rainy ? EGForestType : SnowType;
389 else if (Temperature <= WARM) Type = Rainy ? LForestType : SteppeType;
390 else if (Temperature <= HOT) Type = Rainy ? LForestType : DesertType;
391 else Type = Rainy ? JungleType : DesertType;
392 TypeBuffer[x][y] = Type;
398 void worldmap::SmoothClimate () {
399 for (int c = 0; c < 3; ++c) {
400 game::BusyAnimation();
401 for (int x = 0; x < XSize; ++x)
402 for (int y = 0; y < YSize; ++y)
403 if ((OldTypeBuffer[x][y] = TypeBuffer[x][y]) != OceanType)
404 TypeBuffer[x][y] = WhatTerrainIsMostCommonAroundCurrentTerritorySquareIncludingTheSquareItself(x, y);
406 game::BusyAnimation();
407 for (int x = 0; x < XSize; ++x)
408 for (int y = 0; y < YSize; ++y)
409 Map[x][y]->ChangeGWTerrain
410 (protocontainer<gwterrain>::GetProto(TypeBuffer[x][y])->Spawn());
414 /* Evil... */
415 #define ANALYZE_TYPE(type) {\
416 int T = type;\
417 for (c = 0; c < u; ++c) if (T == UsedType[c]) { ++TypeAmount[c]; break; }\
418 if (c == u) { UsedType[u] = T; TypeAmount[u++] = 1; }\
422 /* k8: WOW! */
423 int worldmap::WhatTerrainIsMostCommonAroundCurrentTerritorySquareIncludingTheSquareItself (int x, int y) {
424 int UsedType[9];
425 int TypeAmount[9];
426 int c, d, u = 1;
427 UsedType[0] = TypeBuffer[x][y];
428 TypeAmount[0] = 1;
429 for (d = 0; d < 4; ++d) {
430 int X = x+DirX[d];
431 int Y = y+DirY[d];
432 if (IsValidPos(X, Y)) ANALYZE_TYPE(OldTypeBuffer[X][Y]);
434 for (d = 4; d < 8; ++d) {
435 int X = x+DirX[d];
436 int Y = y+DirY[d];
437 if (IsValidPos(X, Y)) ANALYZE_TYPE(TypeBuffer[X][Y]);
439 int MostCommon = 0;
440 for (c = 1; c < u; ++c) if (TypeAmount[c] > TypeAmount[MostCommon] && UsedType[c] != OceanType) MostCommon = c;
441 return UsedType[MostCommon];
445 void worldmap::CalculateContinents () {
446 for (uInt c = 1; c < Continent.size(); ++c) delete Continent[c];
447 Continent.resize(1, 0);
448 memset(ContinentBuffer[0], 0, XSizeTimesYSize*sizeof(uChar));
449 game::BusyAnimation();
450 for (int x = 0; x < XSize; ++x) {
451 for (int y = 0; y < YSize; ++y) {
452 if (AltitudeBuffer[x][y] > 0) {
453 truth Attached = false;
454 for (int d = 0; d < 8; ++d) {
455 v2 Pos = v2(x, y)+game::GetMoveVector(d);
456 if (IsValidPos(Pos)) {
457 cint NearCont = ContinentBuffer[Pos.X][Pos.Y];
458 if (NearCont) {
459 cint ThisCont = ContinentBuffer[x][y];
460 if (ThisCont) {
461 if (ThisCont != NearCont) {
462 if (Continent[ThisCont]->GetSize() < Continent[NearCont]->GetSize())
463 Continent[ThisCont]->AttachTo(Continent[NearCont]);
464 else
465 Continent[NearCont]->AttachTo(Continent[ThisCont]);
467 } else Continent[NearCont]->Add(v2(x, y));
468 Attached = true;
472 if (!Attached) {
473 if (Continent.size() == 255) {
474 RemoveEmptyContinents();
475 if (Continent.size() == 255) ABORT("Valpurus shall not carry more continents!");
477 continent *NewContinent = new continent(Continent.size());
478 NewContinent->Add(v2(x, y));
479 Continent.push_back(NewContinent);
484 RemoveEmptyContinents();
485 for (uInt c = 1; c < Continent.size(); ++c) Continent[c]->GenerateInfo();
489 void worldmap::RemoveEmptyContinents () {
490 for (uInt c = 1; c < Continent.size(); ++c) {
491 if (!Continent[c]->GetSize()) {
492 for (uInt i = Continent.size() - 1; i >= c; i--) {
493 if (Continent[i]->GetSize()) {
494 Continent[i]->AttachTo(Continent[c]);
495 delete Continent[i];
496 Continent.pop_back();
497 break;
498 } else {
499 delete Continent[i];
500 Continent.pop_back();
508 void worldmap::Draw (truth) const {
509 cint XMin = Max(game::GetCamera().X, 0);
510 cint YMin = Max(game::GetCamera().Y, 0);
511 cint XMax = Min(XSize, game::GetCamera().X+game::GetScreenXSize());
512 cint YMax = Min(YSize, game::GetCamera().Y+game::GetScreenYSize());
513 blitdata BlitData = {
514 DOUBLE_BUFFER,
515 { 0, 0 },
516 { 0, 0 },
517 { TILE_SIZE, TILE_SIZE },
518 { 0 },
519 TRANSPARENT_COLOR,
520 ALLOW_ANIMATE|ALLOW_ALPHA
522 if (!game::GetSeeWholeMapCheatMode()) {
523 for (int x = XMin; x < XMax; ++x) {
524 BlitData.Dest = game::CalculateScreenCoordinates(v2(x, YMin));
525 wsquare **Square = &Map[x][YMin];
526 for (int y = YMin; y < YMax; ++y, ++Square, BlitData.Dest.Y += TILE_SIZE) {
527 if ((*Square)->LastSeen) (*Square)->Draw(BlitData);
530 } else {
531 for (int x = XMin; x < XMax; ++x) {
532 BlitData.Dest = game::CalculateScreenCoordinates(v2(x, YMin));
533 wsquare **Square = &Map[x][YMin];
534 for (int y = YMin; y < YMax; ++y, ++Square, BlitData.Dest.Y += TILE_SIZE) (*Square)->Draw(BlitData);
540 void worldmap::CalculateLuminances () {
541 for (feuLong c = 0; c < XSizeTimesYSize; ++c) Map[0][c]->CalculateLuminance();
545 void worldmap::CalculateNeighbourBitmapPoses () {
546 for (feuLong c = 0; c < XSizeTimesYSize; ++c) Map[0][c]->GetGWTerrain()->CalculateNeighbourBitmapPoses();
550 wsquare *worldmap::GetNeighbourWSquare (v2 Pos, int I) const {
551 Pos += game::GetMoveVector(I);
552 if (Pos.X >= 0 && Pos.Y >= 0 && Pos.X < XSize && Pos.Y < YSize) return Map[Pos.X][Pos.Y];
553 return 0;
557 void worldmap::RevealEnvironment (v2 Pos, int Radius) {
558 rect Rect;
559 femath::CalculateEnvironmentRectangle(Rect, Border, Pos, Radius);
560 for (int x = Rect.X1; x <= Rect.X2; ++x)
561 for (int y = Rect.Y1; y <= Rect.Y2; ++y)
562 Map[x][y]->SignalSeen();
566 outputfile &operator << (outputfile &SaveFile, const worldmap *WorldMap) {
567 WorldMap->Save(SaveFile);
568 return SaveFile;
572 inputfile &operator >> (inputfile &SaveFile, worldmap *&WorldMap) {
573 WorldMap = new worldmap;
574 WorldMap->Load(SaveFile);
575 return SaveFile;
579 void worldmap::UpdateLOS () {
580 game::RemoveLOSUpdateRequest();
581 int Radius = PLAYER->GetLOSRange();
582 sLong RadiusSquare = Radius*Radius;
583 v2 Pos = PLAYER->GetPos();
584 rect Rect;
585 femath::CalculateEnvironmentRectangle(Rect, Border, Pos, Radius);
586 for (int x = Rect.X1; x <= Rect.X2; ++x)
587 for (int y = Rect.Y1; y <= Rect.Y2; ++y)
588 if (sLong(HypotSquare(Pos.X-x, Pos.Y-y)) <= RadiusSquare) Map[x][y]->SignalSeen();
592 void worldmap::RegisterPlace (owterrain *plc, cint ttype, cint didx, PlaceSpawner spawner) {
593 Places.push_back(plc);
594 PlaceTypes.push_back(ttype);
595 PlaceDungeons.push_back(didx);
596 PlaceSpawners.push_back(spawner);