00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "map.h"
00026 #include <stdio.h>
00027 #include <math.h>
00028 #include <set>
00029
00030 #include "app.h"
00031 #include "frame.h"
00032 #include "glcanvas.h"
00033 #include "profilemanager.h"
00034 #include "parser.h"
00035
00036 extern ofstream logFile;
00037
00038 namespace WDS
00039 {
00040
00041 DECLARE_APP(CApp)
00042
00043
00044 int g_DirTable[8][3] = {
00045
00046 { 0, -1, 8},
00047 { 1, 0, 6},
00048 { 0, 1, 2},
00049 { -1, 0, 4},
00050 { 1, -1, 9},
00051 { 1, 1, 3},
00052 { -1, 1, 1},
00053 { -1, -1, 7} };
00054
00055
00056
00057
00058
00059
00060 CMap::CMap()
00061 {
00062 m_nMapWidth = 0;
00063 m_nMapHeigth = 0;
00064 m_rcBounds = Rect(0, 0, 0, 0);
00065
00066 m_pDlgPath = NULL;
00067 }
00068
00069 CMap::~CMap()
00070 {
00071 Clear( );
00072
00073
00074 if( m_pDlgPath )
00075 {
00076 delete m_pDlgPath;
00077 m_pDlgPath = NULL;
00078 }
00079 }
00080
00081 void CMap::Clear( )
00082 {
00083 m_aTiles.clear();
00084 m_aTowns.clear();
00085 m_nMapWidth = 0;
00086 m_nMapHeigth = 0;
00087 m_rcBounds = Rect( 0, 0, 0, 0);
00088 }
00089
00090
00091
00092
00093
00094 bool CMap::Load( const wxString& strTerrain, const wxString& strTowns )
00095 {
00096
00097 CProfile* p = CProfileManager::GetCurrentProfile();
00098 wxBusyInfo waitInfo( "Bitte warten, lade Profil \"" + p->GetName()
00099 + "\".\nDies kann je nach PC ein paar Sekunden dauern.");
00100
00101
00102 Clear( );
00103
00104
00105 if( !LoadTerrain( strTerrain ) )
00106 return false;
00107
00108
00109 if( !LoadTowns( strTowns ) )
00110 return false;
00111
00112 return true;
00113 }
00114
00126 bool CMap::Update( const string strUpdate )
00127 {
00128 CParser parser;
00129 parser.StartParseString( strUpdate.c_str() );
00130
00131
00132 while( parser.NextToken( true ) )
00133 {
00134
00135 int x = atoi( parser.Token() );
00136
00137
00138 if( !parser.NextToken( false ) ) continue;
00139 int y = atoi( parser.Token() );
00140
00141 m_aTiles[x][y].Reset();
00142 m_aTowns.erase(x, y);
00143
00144
00145 if( !parser.NextToken( false ) ) continue;
00146 m_aTiles[x][y].SetBuilding( atoi(parser.Token()) );
00147
00148
00149 if( !parser.NextToken( false ) ) continue;
00150 m_aTiles[x][y].SetBorder( atoi(parser.Token()) );
00151
00152
00153 if( !parser.NextToken( false ) ) continue;
00154 m_aTiles[x][y].SetStreet( atoi(parser.Token()) );
00155
00156
00157 if( !parser.NextToken( false ) ) continue;
00158
00159
00160 int units = atoi(parser.Token());
00161 if (units & 0x1) m_aTiles[x][y].SetUnit( 1 );
00162 if (units & 0x2) m_aTiles[x][y].SetUnit( 2 );
00163 if (units & 0x4) m_aTiles[x][y].SetUnit( 3 );
00164 if (units & 0x8) m_aTiles[x][y].SetUnit( 4 );
00165
00166
00167 if( !parser.NextToken( false ) ) continue;
00168 m_aTiles[x][y].SetFogOfWar( atoi(parser.Token()) );
00169
00170
00171 if( !parser.NextToken( false ) ) continue;
00172
00173
00174
00175
00176 wxString strName = "", strGuild = "", strOwner = "";
00177 m_aTowns.set( x, y, CTown() );
00178 CTown* pTown = m_aTowns.get( x, y );
00179
00180 pTown->SetPos( x, y );
00181 pTown->SetSight( atoi(parser.Token()) );
00182
00183
00184 if( parser.NextToken( false ) ) strName = parser.Token();
00185
00186
00187 if( parser.NextToken( false ) ) strOwner = parser.Token();
00188
00189
00190 if( parser.NextToken( false ) ) strGuild = parser.Token();
00191
00192 pTown->SetName( strName, strOwner, strGuild );
00193
00194
00195 parser.SkipLine( );
00196 }
00197
00198 return true;
00199 }
00200
00201 bool CMap::LoadTerrain( const wxString& strFile )
00202 {
00203 if( strFile.IsEmpty() )
00204 return false;
00205
00206 wxStopWatch sw;
00207 logFile << "Loading terrrain..." << endl;
00208
00209
00210 FILE *pFile = fopen( strFile.c_str(), "r" );
00211 if( pFile == NULL )
00212 {
00213 logFile << "Konnte Kartendatei '" << strFile.c_str() << "' nicht laden. Bitte 'mapfile' Eintrag in config.cfg überprüfen." << endl;
00214 return false;
00215 }
00216
00217
00218 fseek( pFile, 0L, SEEK_END );
00219 int nSize = ftell( pFile );
00220 rewind( pFile );
00221
00222
00223 BYTE *pFelder = new BYTE[nSize];
00224 memset( pFelder, 0, nSize );
00225
00226
00227 int mx, my = 1;
00228 int nFields = 0;
00229 while( !feof( pFile ) )
00230 {
00231 char c = getc( pFile );
00232
00233 if( c >= '0' && c <= '9' )
00234 {
00235 pFelder[nFields++] = (BYTE)(c-'0');
00236 }
00237 else if( c == '\n' )
00238 {
00239 my++;
00240 }
00241 }
00242 fclose( pFile );
00243
00244
00245 mx = nFields / my;
00246
00247
00248 m_nMapWidth = mx;
00249 m_nMapHeigth = my;
00250 m_aTiles = MapArray( mx, vector<CTile>(my) );
00251
00252
00253 int nTiles = 0;
00254 int x, y;
00255 for ( y = 1; y < my-1; y++)
00256 {
00257 for ( x = 1; x < mx-1; x++ )
00258 {
00259 int nBorder = 0;
00260 int nID = pFelder[x + y*mx];
00261
00262 if ( pFelder[x + (y-1) * mx] != nID ) nBorder = nBorder + 1;
00263 if ( pFelder[x+1 + y * mx] != nID ) nBorder = nBorder + 2;
00264 if ( pFelder[x + (y+1) * mx] != nID ) nBorder = nBorder + 4;
00265 if ( pFelder[x-1 + y * mx] != nID ) nBorder = nBorder + 8;
00266
00267 if (( nBorder & (1+8)) == 0)
00268 if ( pFelder[x-1 + (y-1)*mx] != nID ) nBorder += 16;
00269
00270 if (( nBorder & (1+2)) == 0)
00271 if ( pFelder[x+1 + (y-1)*mx] != nID ) nBorder += 32;
00272
00273 if (( nBorder & (2+4)) == 0)
00274 if ( pFelder[x+1 + (y+1)*mx] != nID ) nBorder += 64;
00275
00276 if (( nBorder & (4+8)) == 0)
00277 if ( pFelder[x-1 + (y+1)*mx] != nID ) nBorder += 128;
00278
00279 m_aTiles[x][y].SetTerrain( nID, nBorder );
00280 nTiles++;
00281 }
00282 }
00283
00284
00285 delete [] pFelder;
00286
00287
00288
00289 for( x = 1; x < mx-1; x++ )
00290 {
00291 m_aTiles[x][0].SetFrame( 3 );
00292 m_aTiles[x][my-1].SetFrame( 6 );
00293 }
00294
00295 for( y=1; y<my-1; y++ )
00296 {
00297 m_aTiles[0][y].SetFrame( 1 );
00298 m_aTiles[mx-1][y].SetFrame( 2 );
00299 }
00300
00301
00302 m_aTiles[0][0].SetFrame( 4 );
00303 m_aTiles[mx-1][0].SetFrame( 5 );
00304 m_aTiles[mx-1][my-1].SetFrame( 8 );
00305 m_aTiles[0][my-1].SetFrame( 7 );
00306
00307
00308 int t = 70;
00309 int l = (0-(my-2)) * 63;
00310 int r = (mx-0) * 63;
00311 int b = (my+mx) * 35;
00312 m_rcBounds.x = l;
00313 m_rcBounds.y = t;
00314 m_rcBounds.w = r-l;
00315 m_rcBounds.h = b-t;
00316 m_rcBounds.Inflate( 100, 100 );
00317
00318 logFile << "-> " << nFields << " terrain tiles loaded in " << sw.Time() << " ms." << endl;
00319
00320 return true;
00321 }
00322
00323 bool CMap::LoadTowns( const wxString& strFile )
00324 {
00325 if( strFile.IsEmpty() )
00326 return false;
00327
00328
00329 ifstream infile( strFile.c_str() );
00330 if ( infile.fail() )
00331 {
00332 logFile << "Konnte Datendatei '" << strFile.c_str() << "' nicht laden. Bitte 'datfile' Eintrag in config.cfg überprüfen." << endl;
00333 return false;
00334 }
00335
00336 char c;
00337 string strToken;
00338 while( !infile.eof() )
00339 {
00340 infile >> c;
00341 if( c == '[' )
00342 {
00343 infile >> strToken;
00344
00345 if( strToken.find( "buildings" ) != string::npos )
00346 LoadBuildings( infile );
00347
00348 else if( strToken.find( "border" ) != string::npos )
00349 LoadBorders( infile );
00350
00351 else if( strToken.find( "units" ) != string::npos )
00352 LoadUnits( infile );
00353
00354 else if( strToken.find( "streets" ) != string::npos )
00355 LoadStreets( infile );
00356
00357 else if( strToken.find( "towns" ) != string::npos )
00358 LoadTowns( infile );
00359 }
00360
00361 }
00362
00363 infile.close();
00364
00365 return true;
00366 }
00367
00368 bool CMap::LoadBuildings( ifstream &infile )
00369 {
00370 wxStopWatch sw;
00371 logFile << "Loading buildings..." << endl;
00372
00373 int x, y, n;
00374 int nBuildings = 0;
00375 while( 1 )
00376 {
00377 eatwhite( infile );
00378 if( infile.eof() || infile.peek() == '[')
00379 break;
00380
00381 infile >> x >> y >> n;
00382
00383 m_aTiles[x][y].SetBuilding( n );
00384 nBuildings++;
00385 }
00386
00387 logFile << "-> " << nBuildings << " buildings loaded in " << sw.Time() << " ms." << endl;
00388
00389 return true;
00390 }
00391
00392 bool CMap::LoadBorders( ifstream &infile )
00393 {
00394 wxStopWatch sw;
00395 logFile << "Loading borders..." << endl;
00396
00397 int x, y, n;
00398 int nBorders = 0;
00399 while( 1 )
00400 {
00401 eatwhite( infile );
00402 if( infile.eof() || infile.peek() == '[')
00403 break;
00404
00405 infile >> x >> y >> n;
00406 m_aTiles[x][y].SetBorder( n );
00407 nBorders++;
00408 }
00409
00410 logFile << "-> " << nBorders << " borders loaded in " << sw.Time() << " ms." << endl;
00411
00412 return true;
00413 }
00414
00415 bool CMap::LoadUnits( ifstream &infile )
00416 {
00417 wxStopWatch sw;
00418 logFile << "Loading units..." << endl;
00419
00420 int x, y, n;
00421 int nUnits = 0;
00422 while( 1 )
00423 {
00424 eatwhite( infile );
00425 if( infile.eof() || infile.peek() == '[')
00426 break;
00427
00428 infile >> x >> y >> n;
00429 m_aTiles[x][y].SetUnit( n );
00430 nUnits++;
00431 }
00432
00433 logFile << "-> " << nUnits << " units loaded in " << sw.Time() << " ms." << endl;
00434
00435 return true;
00436 }
00437
00438 bool CMap::LoadStreets( ifstream &infile )
00439 {
00440 wxStopWatch sw;
00441 logFile << "Loading streets..." << endl;
00442
00443 int x, y, n;
00444 int nStreets = 0;
00445 while( 1 )
00446 {
00447 eatwhite( infile );
00448 if( infile.eof() || infile.peek() == '[')
00449 break;
00450
00451 infile >> x >> y >> n;
00452 m_aTiles[x][y].SetStreet( n );
00453 nStreets++;
00454 }
00455
00456 logFile << "-> " << nStreets << " streets loaded in " << sw.Time() << " ms." << endl;
00457
00458 return true;
00459 }
00460
00461
00462
00463
00464
00465 bool CMap::LoadTowns( ifstream &infile )
00466 {
00467 wxStopWatch sw;
00468 logFile << "Loading towns..." << endl;
00469
00470 int x, y;
00471 char buf[64], c;
00472 wxString strName, strOwner, strGuild;
00473 int nTowns = 0;
00474 CTown town;
00475 while( 1 )
00476 {
00477 eatwhite( infile );
00478 if( infile.eof() || infile.peek() == '[')
00479 break;
00480
00481 infile >> x >> y;
00482
00483 infile >> c;
00484 infile.getline(buf, 63, '"' );
00485 strName = buf;
00486
00487 infile >> c;
00488 infile.getline(buf, 63, '"' );
00489 strOwner = buf;
00490
00491 infile >> c;
00492 infile.getline(buf, 63, '"' );
00493 strGuild = buf;
00494
00495 town.SetName( strName, strOwner, strGuild );
00496 town.SetPos( x, y );
00497 m_aTowns.set( x, y, town );
00498 nTowns++;
00499 }
00500
00501 logFile << "-> " << nTowns << " towns loaded in " << sw.Time() << " ms." << endl;
00502
00503 return true;
00504 }
00505
00506
00507
00508
00509
00510
00511 void CMap::Draw()
00512 {
00513 int x, y;
00514 CGLCanvas *pCanvas = GetGLCanvas();
00515 CProfile *pProfile = CProfileManager::GetCurrentProfile( );
00516 bool bFOW = pProfile->GetFogOfWar( );
00517 Rect rcScreen = pCanvas->GetVisibleRect();
00518 Rect rcTile( 0, 0, 126, 105 );
00519
00520 int sx = GetFieldAtPoint( rcScreen.x, rcScreen.y ).x;
00521 int mx = GetFieldAtPoint( rcScreen.x + rcScreen.w + 128, rcScreen.y + rcScreen.h ).x;
00522
00523 int sy = GetFieldAtPoint( rcScreen.x + rcScreen.w, rcScreen.y ).y;
00524 int my = GetFieldAtPoint( rcScreen.x, rcScreen.y + rcScreen.h + 128 ).y;
00525
00526
00527 for ( y=sy; y<my; y++ )
00528 {
00529 for ( x=sx; x<mx; x++ )
00530 {
00531 rcTile.x = (x-y) * 63;
00532 rcTile.y = (y+x) * 35;
00533
00534 if( rcScreen.RectIntersect( &rcTile ) )
00535 {
00536 m_aTiles[x][y].Draw( rcTile, bFOW );
00537 }
00538 }
00539 }
00540
00541
00542 for ( y=sy; y<my; y++ )
00543 {
00544 for ( x=sx; x<mx; x++ )
00545 {
00546 rcTile.x = (x-y) * 63;
00547 rcTile.y = (y+x) * 35;
00548
00549 if( rcScreen.RectIntersect( &rcTile ) )
00550 {
00551 m_aTiles[x][y].DrawOverlay( rcTile );
00552 }
00553 }
00554 }
00555
00556
00557 bool bShowTownNames;
00558 double fHideTownNames;
00559 wxConfigBase::Get()->SetPath( "/General" );
00560 wxConfigBase::Get()->Read( "show_town_names", &bShowTownNames, true );
00561 wxConfigBase::Get()->Read( "hide_town_names", &fHideTownNames, 0.2 );
00562
00563
00564 if( bShowTownNames && pCanvas->GetZoom() > fHideTownNames )
00565 {
00566 CTown* pTown = m_aTowns.firstSibling();
00567
00568 while ( pTown != 0L ) {
00569
00570
00571 pTown->Draw( &rcScreen );
00572
00573 pTown = m_aTowns.nextSibling();
00574 }
00575 }
00576 }
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586 bool CMap::FindPath( int sx, int sy, int ex, int ey )
00587 {
00588 wxBusyCursor bc;
00589
00590
00591 if( !IsValidField( sx, sy ) ||
00592 !IsValidField( ex, ey ) )
00593 {
00594 wxMessageBox( "Start oder Ziel ist nicht erreichbar!", "Fehler" );
00595 return false;
00596 }
00597
00598
00599 for(int y=0; y<m_nMapHeigth; y++ )
00600 {
00601 for(int x=0; x<m_nMapWidth; x++ )
00602 {
00603 m_aTiles[x][y].m_Parent = -1;
00604 m_aTiles[x][y].m_CostF = 0;
00605 m_aTiles[x][y].m_CostG = 0;
00606 m_aTiles[x][y].m_State = PATH_NONE;
00607 }
00608 }
00609
00610 wxStopWatch sw;
00611 bool bRet = AStar( sx, sy, ex, ey );
00612 sw.Pause();
00613
00614 if( bRet )
00615 {
00616 wxString strPath;
00617
00618
00619 CTile *pTile;
00620 float fCost = 0.0f;
00621 int x = ex;
00622 int y = ey;
00623 int nParent;
00624
00625 while( 1 )
00626 {
00627 pTile = &m_aTiles[x][y];
00628 pTile->m_State = PATH_ACTIVE;
00629 nParent = pTile->m_Parent;
00630
00631
00632 if( nParent == -1 )
00633 break;
00634
00635 x -= g_DirTable[nParent][0];
00636 y -= g_DirTable[nParent][1];
00637 fCost += pTile->GetWeigth();
00638
00639
00640 strPath = ((char)(g_DirTable[nParent][2]+'0')) + strPath;
00641 }
00642
00643 GetGLCanvas()->Refresh( );
00644
00645
00646 if( !m_pDlgPath )
00647 {
00648 m_pDlgPath = new CDlgPath( sx, sy, ex, ey, sw.Time(), fCost, strPath, wxGetApp().GetFrame() );
00649 m_pDlgPath->Center();
00650 }
00651 else
00652 {
00653 m_pDlgPath->UpdateValues( sx, sy, ex, ey, sw.Time(), fCost, strPath );
00654 }
00655
00656 m_pDlgPath->Show();
00657 }
00658 else
00659 {
00660 wxMessageBox( wxString::Format( "Kein Pfad von %d:%d nach %d:%d gefunden!",
00661 sx, sy, ex, ey), "Fehler" );
00662 }
00663
00664 return bRet;
00665 }
00666
00667 bool CMap::AStar( int sx, int sy, int ex, int ey )
00668 {
00669
00670 multiset<PathField> queue;
00671 multiset<PathField>::iterator itr;
00672
00673
00674 CTile *pTile = &m_aTiles[sx][sy];
00675 pTile->m_CostG = 0;
00676 pTile->m_CostF = Heuristic( sx, sy, ex, ey );
00677 pTile->m_State = PATH_OPEN;
00678 queue.insert( PathField(sx, sy, pTile) );
00679
00680
00681 while( !queue.empty() )
00682 {
00683
00684 PathField f = *queue.begin();
00685 queue.erase( queue.begin() );
00686
00687 f.pTile->m_State = PATH_CLOSE;
00688 int x = f.x, y = f.y;
00689
00690
00691 if( x == ex && y == ey )
00692 return true;
00693
00694
00695 for( int i=0; i<8; i++ )
00696 {
00697
00698 int ax = x + g_DirTable[i][0];
00699 int ay = y + g_DirTable[i][1];
00700
00701
00702 if( !IsValidField( ax, ay ) )
00703 continue;
00704
00705 pTile = &m_aTiles[ax][ay];
00706
00707
00708 float G = f.pTile->m_CostG + pTile->GetWeigth();
00709
00710
00711 if( pTile->m_State == PATH_CLOSE && pTile->m_CostG < G )
00712 continue;
00713
00714
00715 if( pTile->m_State == PATH_OPEN )
00716 {
00717 if( pTile->m_CostG < G )
00718 continue;
00719
00720
00721 itr = queue.find( PathField( ax, ay, pTile ) );
00722 if( itr != queue.end() )
00723 {
00724
00725
00726 while( (*itr).pTile != pTile )
00727 itr++;
00728
00729 queue.erase( itr );
00730 }
00731 }
00732
00733
00734 pTile->m_CostG = G;
00735 pTile->m_CostF = G + Heuristic( ax, ay, ex, ey );
00736 pTile->m_Parent = i;
00737
00738
00739 pTile->m_State = PATH_OPEN;
00740 queue.insert( PathField(ax, ay, pTile) );
00741 }
00742 }
00743
00744
00745 return false;
00746 }
00747
00748 float CMap::Heuristic( int sx, int sy, int ex, int ey )
00749 {
00750 int dx = abs( sx - ex );
00751 int dy = abs( sy - ey );
00752
00753
00754 return ( 1 * max(dx, dy));
00755 }
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765 bool CMap::IsValidField( int x, int y )
00766 {
00767 if( x <= 0 || y <= 0 || x >= (m_nMapWidth-1) || y >= (m_nMapHeigth-1) )
00768 return false;
00769
00770 return true;
00771 }
00772
00773
00774
00775
00776
00777 wxPoint CMap::GetFieldAtPoint( int x, int y )
00778 {
00779 wxPoint pt;
00780 pt.x = int((double(x) / 126.0 + double(y) / 70.0) - 1.0);
00781 pt.y = int( double(y) / 70.0 - double(x) / 126.0);
00782
00783
00784 if( pt.x < 0 ) pt.x = 0; else if( pt.x > m_nMapWidth ) pt.x = m_nMapWidth;
00785 if( pt.y < 0 ) pt.y = 0; else if( pt.y > m_nMapHeigth ) pt.y = m_nMapHeigth;
00786 return pt;
00787 }
00788
00789
00790
00791
00792
00793 wxPoint CMap::GetPosFromField( int x, int y )
00794 {
00795 wxPoint pt;
00796 pt.x = (x-y) * 63 + 60;
00797 pt.y = (y+x) * 35 + 70;
00798 return pt;
00799 }
00800
00807 CTown* CMap::GetTownAt( int x, int y )
00808 {
00809 if ( !IsValidField( x, y ) )
00810 return NULL;
00811
00812 return m_aTowns.get( x, y );
00813 }
00814
00815 CGLCanvas* CMap::GetGLCanvas()
00816 {
00817 CGLCanvas *pCanvas = wxGetApp().GetFrame()->GetGLCanvas();
00818 return pCanvas;
00819 }
00820
00821 }
00822