Main Page | Class List | File List | Class Members | Related Pages

map.cpp

00001 /***************************************************************************
00002                            map.cpp
00003                            -------------------
00004     begin                : 2004-04-16
00005     copyright            : (C) 2004-2005 by Michael Menne
00006     email                : menne@users.sourceforge.net
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  This program is free software; you can redistribute it and/or
00011  modify it under the terms of the GNU General Public License
00012  as published by the Free Software Foundation; either version 2
00013  of the License, or (at your option) any later version.
00014 
00015  This program is distributed in the hope that it will be useful,
00016  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  GNU General Public License for more details.
00019 
00020  You should have received a copy of the GNU General Public License
00021  along with this program; if not, write to the Free Software
00022  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
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 // Direction Table for Paths
00044 int g_DirTable[8][3] = {
00045 // x   y  WDS-Keypad
00046 {  0, -1, 8},       // oben
00047 {  1,  0, 6},       // rechts
00048 {  0,  1, 2},       // unten
00049 { -1,  0, 4},       // links
00050 {  1, -1, 9},       // rechts-oben
00051 {  1,  1, 3},       // rechts-unten
00052 { -1,  1, 1},       // links-unten
00053 { -1, -1, 7} };     // links-oben
00054 
00055 
00056 /*----------------------------------------------------------------------------/
00057     Constructor / Destructor
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     // Pfad-Dialog löschen
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     Lade Funktionen
00092 -----------------------------------------------------------------------------*/
00093 
00094 bool CMap::Load( const wxString& strTerrain, const wxString& strTowns )
00095 {
00096     // if CMap::Load is called, we can be sure that p != NULL
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     // Alte Karte loeschen
00102     Clear( );
00103 
00104     // Terrain laden
00105     if( !LoadTerrain( strTerrain ) )
00106         return false;
00107 
00108     // Towns laden
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     // Solange parsen, bis nichts mehr da ist
00132     while( parser.NextToken( true ) )
00133     {
00134         // X-Koordinate
00135         int x = atoi( parser.Token() );
00136 
00137         // Y-Koordinate
00138         if( !parser.NextToken( false ) ) continue;
00139         int y = atoi( parser.Token() );
00140 
00141         m_aTiles[x][y].Reset(); // reset data for that tile
00142         m_aTowns.erase(x, y);   // and remove town if it exists
00143 
00144         // [BUILDING]
00145         if( !parser.NextToken( false ) ) continue;
00146         m_aTiles[x][y].SetBuilding( atoi(parser.Token()) );
00147 
00148         // [BORDERS]
00149         if( !parser.NextToken( false ) ) continue;
00150         m_aTiles[x][y].SetBorder( atoi(parser.Token()) );
00151 
00152         // [STREETS]
00153         if( !parser.NextToken( false ) ) continue;
00154         m_aTiles[x][y].SetStreet( atoi(parser.Token()) );
00155 
00156         // [UNITS]
00157         if( !parser.NextToken( false ) ) continue;
00158 
00159         // extract the units and set them
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         // [FOW] (fog of war)
00167         if( !parser.NextToken( false ) ) continue;
00168         m_aTiles[x][y].SetFogOfWar( atoi(parser.Token()) );
00169 
00170         // [SIGHT]
00171         if( !parser.NextToken( false ) ) continue;
00172 
00173 
00174         // ok, now we *know* that at x, y is a town, so add entry to town array
00175         // and create needed variables.
00176         wxString strName = "", strGuild = "", strOwner = "";
00177         m_aTowns.set( x, y, CTown() );
00178         CTown* pTown = m_aTowns.get( x, y ); // get pointer to the new town
00179 
00180         pTown->SetPos( x, y );
00181         pTown->SetSight( atoi(parser.Token()) );
00182 
00183         // [TOWN_NAME]
00184         if( parser.NextToken( false ) ) strName = parser.Token();
00185 
00186         // [PLAYER_NAME]
00187         if( parser.NextToken( false ) ) strOwner = parser.Token();
00188 
00189         // [GUILD]
00190         if( parser.NextToken( false ) ) strGuild = parser.Token();
00191 
00192         pTown->SetName( strName, strOwner, strGuild );
00193 
00194 
00195         parser.SkipLine( ); // Rest der Zeile überspringen
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     // Input Datei oeffnen
00210     FILE *pFile = fopen( strFile.c_str(), "r" );    // FILE ist schneller als ifstream!
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     // Größe der Datei abfragen
00218     fseek( pFile, 0L, SEEK_END );
00219     int nSize = ftell( pFile );
00220     rewind( pFile );
00221 
00222     // Speicher für die CSV-Daten reservieren
00223     BYTE *pFelder = new BYTE[nSize];
00224     memset( pFelder, 0, nSize );
00225 
00226     // CSV-Daten einlesen
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' )  // Is c a number?
00234         {
00235             pFelder[nFields++] = (BYTE)(c-'0');
00236         }
00237         else if( c == '\n' )
00238         {
00239             my++;
00240         }
00241     }
00242     fclose( pFile );
00243 
00244     // Breite der Karte berechnen
00245     mx = nFields / my;
00246 
00247     // Speicher für die Karte reservieren
00248     m_nMapWidth  = mx;
00249     m_nMapHeigth = my;
00250     m_aTiles = MapArray( mx, vector<CTile>(my) );
00251 
00252     // Die genauen Bilder aus den CSV-Daten brechnen
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;  // Oben
00263             if ( pFelder[x+1 +  y    * mx] != nID ) nBorder = nBorder + 2;  // Rechts
00264             if ( pFelder[x   + (y+1) * mx] != nID ) nBorder = nBorder + 4;  // Unten
00265             if ( pFelder[x-1 +  y    * mx] != nID ) nBorder = nBorder + 8;  // Links
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     // CSV-Daten löschen
00285     delete [] pFelder;
00286 
00287 
00288     // Rahmen hinzufügen
00289     for( x = 1; x < mx-1; x++ ) // Obenere und untenere Leiste des Rahmens
00290     {
00291         m_aTiles[x][0].SetFrame( 3 );      // Oben
00292         m_aTiles[x][my-1].SetFrame( 6 ); // Unten
00293     }
00294 
00295     for( y=1; y<my-1; y++ )     // Linke und rechte Leiste des Rahmens
00296     {
00297         m_aTiles[0][y].SetFrame( 1 );    // Links
00298         m_aTiles[mx-1][y].SetFrame( 2 ); // Rechts
00299     }
00300 
00301     // Ecken des Rahmen
00302     m_aTiles[0][0].SetFrame( 4 );         // Oben links
00303     m_aTiles[mx-1][0].SetFrame( 5 );      // Oben rechts
00304     m_aTiles[mx-1][my-1].SetFrame( 8 ); // Unten rechts
00305     m_aTiles[0][my-1].SetFrame( 7 );    // Unten links
00306 
00307     // Umgebungs-Box berechnen
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     // Input Datei öffnen
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  *  LoadTowns( )
00463  *  Bsp.: 344 372 "Coronet" "Smir" "[BDS]"
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;            // c ist "
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     Zeichen Funktionen
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;                                   // Top-Left
00521     int mx = GetFieldAtPoint( rcScreen.x + rcScreen.w + 128, rcScreen.y + rcScreen.h ).x;   // Botton-Right
00522 
00523     int sy = GetFieldAtPoint( rcScreen.x + rcScreen.w, rcScreen.y ).y;          // Top-Right
00524     int my = GetFieldAtPoint( rcScreen.x, rcScreen.y + rcScreen.h + 128 ).y;    // Bottom-Left
00525 
00526     // Draw visible region
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     // Draw overlays
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     // Werte für das zeichnen der Städtenamen aus der Configdatei auslesen
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 );   // TODO: Bloeder Name.
00562 
00563     // Städtenamen zeichnen.
00564     if( bShowTownNames && pCanvas->GetZoom() > fHideTownNames ) // Keine Namen wenn zu weit weggezoomt!
00565     {
00566         CTown* pTown = m_aTowns.firstSibling();
00567 
00568         while ( pTown != 0L ) {
00569             // Jeder Stadtname wird gegen den sichtbaren Bereich getestet.
00570             // Dies ist nicht schnell, geht aber bei den wenigen Städten die wir haben.
00571             pTown->Draw( &rcScreen );
00572 
00573             pTown = m_aTowns.nextSibling();
00574         }
00575     }
00576 }
00577 
00578 /*----------------------------------------------------------------------------/
00579     Pfadfinde Funktionen
00580 -----------------------------------------------------------------------------*/
00581 
00582 /*
00583  *  FindPath
00584  *  Bei Erfolg wird die Länge des Pfades zurückgegeben, sonst -1
00585  */
00586 bool CMap::FindPath( int sx, int sy, int ex, int ey )
00587 {
00588     wxBusyCursor bc;
00589 
00590     // Testen ob Start und Endpunkte erreichbar sind
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     // Tilearray zurücksetzen
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         // Den Weg vom Ziel zum Start zurückverfolgen und markieren
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;   // Liegt auf dem Weg
00629             nParent = pTile->m_Parent;
00630 
00631             // Abbrechen wenn wir am Startknoten angekommen sind
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             // Pfadstring zusammensetzen
00640             strPath = ((char)(g_DirTable[nParent][2]+'0')) + strPath;
00641         }
00642 
00643         GetGLCanvas()->Refresh( );
00644 
00645         // Path Dialog anzeigen
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     // Multiset sowie ein Iterator
00670     multiset<PathField> queue;
00671     multiset<PathField>::iterator itr;
00672 
00673     // 1.Add starting square
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     // Schleife
00681     while( !queue.empty() )
00682     {
00683         // Knoten mit den niedrigsten Kosten aus der Liste holen
00684         PathField f = *queue.begin();
00685         queue.erase( queue.begin() );
00686 
00687         f.pTile->m_State = PATH_CLOSE;  // Jetzt geschlossen
00688         int x = f.x, y = f.y;
00689 
00690         // Wenn Ziel sind wir fertig
00691         if( x == ex && y == ey )
00692             return true;
00693 
00694         // Alle angrenzenden Felder bearbeiten
00695         for( int i=0; i<8; i++ )
00696         {
00697             // Nachbarzelle
00698             int ax = x + g_DirTable[i][0];
00699             int ay = y + g_DirTable[i][1];
00700 
00701             // Testen ob neue x/y-Position gültig ist ( Rand ist ausgenommen )
00702             if( !IsValidField( ax, ay ) )
00703                 continue;
00704 
00705             pTile = &m_aTiles[ax][ay];
00706 
00707             // Kosten um zu diesem Feld zu gelangen:
00708             float G = f.pTile->m_CostG + pTile->GetWeigth();    // Vorherige + aktuelle Kosten vom Start
00709 
00710             // Ignorieren wenn Knoten geschlossen ist und bessere Kosten hat
00711             if( pTile->m_State == PATH_CLOSE  && pTile->m_CostG < G )
00712                 continue;
00713 
00714             // Tile ist bereits in der Queue, nur ersetzen wenn Kosten besser
00715             if( pTile->m_State == PATH_OPEN )
00716             {
00717                 if( pTile->m_CostG < G )
00718                     continue;
00719 
00720                 // Alten Eintrag aus der Queue entfernen
00721                 itr = queue.find( PathField( ax, ay, pTile ) );
00722                 if( itr != queue.end() )
00723                 {
00724                     // Es können mehrere Einträge mit den gleichen Kosten vorhanden sein
00725                     // wir müssen den richtigen suchen
00726                     while( (*itr).pTile != pTile )
00727                         itr++;
00728 
00729                     queue.erase( itr );
00730                 }
00731             }
00732 
00733             // Knoten berechnen
00734             pTile->m_CostG  = G;
00735             pTile->m_CostF  = G + Heuristic( ax, ay, ex, ey );      // Kosten vom Start + Kosten zum Ziel
00736             pTile->m_Parent = i;
00737 
00738             // Zu OPEN hinzufügen
00739             pTile->m_State = PATH_OPEN;
00740             queue.insert( PathField(ax, ay, pTile) );
00741         }
00742     }
00743 
00744     // Keinen Pfad gefunden
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     // Je größer die Konstante je schneller die Pfadplanung, je kleiner je optimaler der Weg
00754     return ( 1 * max(dx, dy));
00755 }
00756 
00757 /*----------------------------------------------------------------------------/
00758     Sonstige Funktionen
00759 -----------------------------------------------------------------------------*/
00760 
00761 /*
00762  *  IsValidField
00763  *  Wenn das Feld x/y exestiert, wird true zurückgegeben, sonst false
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  *  GetFieldAtPoint
00775  *  Liefert die x/y Koordinate des Feldes unter dem Pixel an der Koordinate (x,y)
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     // Clamp to valid map dimensions
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  *  GetPosFromField
00791  *  Gibt die x/y Koordinate des Feldes (Mittepunkt) in Pixeln zurück
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 // kate: space-indent off; tab-width 4; replace-tabs off;

Generated on Sun Jan 16 18:20:26 2005 for WDSMap by  doxygen 1.3.9.1