1 /* $Id: map.hpp,v 1.74.4.1 2006/01/20 11:23:31 chfreund Exp $ */ 2 3 /******************************************************************************/ 4 5 #ifndef _MAP_HPP_ 6 #define _MAP_HPP_ 7 8 /******************************************************************************/ 9 10 #include <SDL.h> 11 12 #include "global.hpp" 13 #include "string.hpp" 14 #include "serializable.hpp" 15 #include "serialize.hpp" 16 #include "mapmemory.hpp" 17 #include "flag.hpp" 18 #include "theme.hpp" 19 #include "graphics.hpp" 20 21 /******************************************************************************/ 22 23 // forward declaration needed for method ServerMap::createFromTheme 24 class World; 25 26 ////////////////////////////////////////////////////////////////////// 27 // Map contains the 'static' part of the battleground (e.g. a 28 // background, the foreground pixels, flags for each pixel etc) 29 ////////////////////////////////////////////////////////////////////// 30 31 /******************************************************************************/ 32 33 class Map { 34 protected: 35 //! sets entire flag field to zero 36 void initializeFlags( void ); 37 //! m_sizeX is the width, m_sizeY the height of the map 38 Uint32 m_sizeX, m_sizeY; 39 //! A flag field e.g. for marking obstacles 40 MapMemory<Flag> m_flags; 41 42 /******************************************************************************/ 43 44 public: Map(Uint32 sizeX,Uint32 sizeY)45 Map( Uint32 sizeX, Uint32 sizeY ) 46 : m_sizeX( sizeX ), m_sizeY( sizeY ), 47 m_flags( sizeX, sizeY ) { 48 initializeFlags(); 49 } 50 51 /******************************************************************************/ 52 Map(MapMemory<Flag> & flags)53 Map( MapMemory<Flag>& flags ) 54 : m_sizeX( flags.getSizeX() ), m_sizeY( flags.getSizeY() ), 55 m_flags( flags ) { 56 } 57 58 /******************************************************************************/ 59 ~Map()60 virtual ~Map() { } 61 62 /******************************************************************************/ 63 64 // returns the width of the map getSizeX() const65 Uint32 getSizeX() const { 66 return m_sizeX; 67 } 68 69 /******************************************************************************/ 70 71 // returns the height of the map getSizeY() const72 Uint32 getSizeY() const { 73 return m_sizeY; 74 } 75 76 /******************************************************************************/ 77 78 // returns a pointer to the flag container getFlags()79 MapMemory<Flag>* getFlags() { 80 return &m_flags; 81 } 82 83 /******************************************************************************/ 84 85 //! \name methods concerning map creation from a theme definition 86 //@{ 87 //! creates a map from a theme 88 void createFromTheme( Theme& theme, World& world ); 89 //! fills the map with random circles 90 void fillWithRandomCircles(); 91 //! places the passed sprite as map stuff of passed material 92 void placeMapStuffItem( const Sprite* const item, 93 const Sprite* const flags, 94 const Uint32 x, const Uint32 y, 95 const int material, 96 const bool smoothable = true ); 97 //! places the passed sprite as map stuff of passed material placeMapStuffItem(const Sprite * const item,const Uint32 x,const Uint32 y,const int material,const bool smoothable=true)98 void placeMapStuffItem( const Sprite* const item, 99 const Uint32 x, const Uint32 y, 100 const int material, 101 const bool smoothable = true ) { 102 placeMapStuffItem( item, item, x, y, material, smoothable ); 103 } 104 //@} 105 106 void displayFlags(); 107 bool saveFlags( const char* comment ); 108 109 virtual void getColorAt( const Uint32 x, const Uint32 y, 110 Uint8& red, Uint8& green, Uint8& blue ) = 0; 111 virtual void setColorAt( const Uint32 x, const Uint32 y, 112 const Uint8 r, const Uint8 g, const Uint8 b ) = 0; 113 virtual void setColorAt( const Uint32 x, const Uint32 y, const Uint32 color ) = 0; 114 115 /******************************************************************************/ 116 destroyEarthPixel(const Uint32 x,const Uint32 y,const Flag mask)117 void destroyEarthPixel( const Uint32 x, const Uint32 y, const Flag mask ) { 118 Flag& flag = m_flags.getReferenceTo( x, y ); 119 120 if( (flag & Flags::OBSTACLE_EARTH) && ! (flag & mask) ) { 121 LOG( 5 ) INFO( "Map::destroyEarthPixel: at (%i, %i)\n", x, y ); 122 flag = 0; 123 setColorAt( x, y, 0, 0, 0 ); 124 } 125 } 126 127 /******************************************************************************/ 128 destroyEarthPixelClip(const Uint32 x,const Uint32 y,const Flag mask)129 void destroyEarthPixelClip( const Uint32 x, const Uint32 y, const Flag mask ) { 130 if( x < m_sizeX && y < m_sizeY ) { 131 destroyEarthPixel( x, y, mask ); 132 } 133 } 134 135 //! combines all flags in the specified rectangle with binary OR 136 137 /*! Combines all map flags in a rectangular area with the binary 138 * OR operator and returns this value. The rectange area is 139 * specified by passing its uper left corner (x1,y1) and its 140 * bottom right corner (x2,y2). This means that the rectangle 141 * includes the points (x1,y1) and (x2,y2). 142 */ getOrCombinedFlagsInRect(Sint32 x1,Sint32 y1,Sint32 x2,Sint32 y2)143 Flag getOrCombinedFlagsInRect( Sint32 x1, Sint32 y1, 144 Sint32 x2, Sint32 y2 ) { 145 if( x1 < 0 ) x1 = 0; 146 if( y1 < 0 ) y1 = 0; 147 if( ++x2 > (Sint32)m_sizeX ) x2 = (Sint32)m_sizeX; 148 if( ++y2 > (Sint32)m_sizeY ) y2 = (Sint32)m_sizeY; 149 150 Flag orCollected = 0; 151 for( int y = y1; y < y2; y++ ) { 152 for( int x = x1; x < x2; x++ ) { 153 orCollected |= m_flags.getValueAt( x, y ); 154 } 155 } 156 return orCollected; 157 } 158 159 /******************************************************************************/ 160 testPassable(const Uint32 x,const Uint32 y,const Flag mask)161 bool testPassable( const Uint32 x, const Uint32 y, const Flag mask ) { 162 return ! (m_flags.getValueAt( x, y ) & mask); 163 } 164 165 /******************************************************************************/ 166 testPassableClip(const Uint32 x,const Uint32 y,const Flag mask)167 bool testPassableClip( const Uint32 x, const Uint32 y, const Flag mask ) { 168 if( x >= m_sizeX || y >= m_sizeY ) return false; 169 return ! (m_flags.getValueAt( x, y ) & mask); 170 } 171 172 /******************************************************************************/ 173 testPassableSmoothing(const Uint32 x,const Uint32 y,const Flag mask)174 bool testPassableSmoothing( const Uint32 x, const Uint32 y, 175 const Flag mask ) { 176 DBG( 5 ) { 177 if( x >= m_sizeX || y >= m_sizeY ) { 178 CHECK( false, "Map::testPassableSmoothing: coordinates out of bounds: " 179 "(%3i, %3i)\n", x, y ); 180 return false; 181 } 182 } 183 184 const Flag& flag = m_flags.getReferenceTo( x, y ); 185 186 if( ! (flag & mask) ) { 187 /* 188 int passableNeighbors = 0; 189 if( m_flags.getValueAt( x-1, y-1 ) & Flag::PASSABLE ) passableNeighbors++; 190 if( m_flags.getValueAt( x , y-1 ) & Flag::PASSABLE ) passableNeighbors++; 191 if( m_flags.getValueAt( x+1, y-1 ) & Flag::PASSABLE ) passableNeighbors++; 192 if( m_flags.getValueAt( x-1, y ) & Flag::PASSABLE ) passableNeighbors++; 193 if( m_flags.getValueAt( x+1, y ) & Flag::PASSABLE ) passableNeighbors++; 194 if( m_flags.getValueAt( x-1, y+1 ) & Flag::PASSABLE ) passableNeighbors++; 195 if( m_flags.getValueAt( x , y+1 ) & Flag::PASSABLE ) passableNeighbors++; 196 if( m_flags.getValueAt( x+1, y+1 ) & Flag::PASSABLE ) passableNeighbors++; 197 198 if( passableNeighbors <= 3 ) { 199 LOG( 4 ) INFO( "Map::testPassableSmoothing: isolated hole => fill pixel\n" ); 200 m_flags.getReferenceTo( x, y ) &= ~Flag::PASSABLE; 201 m_pixels.setValueAt( x, y, 0x00ff00 ); 202 return false; 203 }*/ 204 return true; 205 } 206 else { 207 if( ! (flag & Flags::UNSMOOTHABLE) ) { 208 int passableNeighbors = 0; 209 if( ! (m_flags.getValueAt( x-1, y-1 ) & mask) ) passableNeighbors++; 210 if( ! (m_flags.getValueAt( x , y-1 ) & mask) ) passableNeighbors++; 211 if( ! (m_flags.getValueAt( x+1, y-1 ) & mask) ) passableNeighbors++; 212 if( ! (m_flags.getValueAt( x-1, y ) & mask) ) passableNeighbors++; 213 if( ! (m_flags.getValueAt( x+1, y ) & mask) ) passableNeighbors++; 214 if( ! (m_flags.getValueAt( x-1, y+1 ) & mask) ) passableNeighbors++; 215 if( ! (m_flags.getValueAt( x , y+1 ) & mask) ) passableNeighbors++; 216 if( ! (m_flags.getValueAt( x+1, y+1 ) & mask) ) passableNeighbors++; 217 218 if( passableNeighbors >= 5 ) { 219 LOG( 5 ) INFO( "Map::testPassableSmoothing: isolated pixel => destroy pixel\n" ); 220 destroyEarthPixel( x, y, 0 ); 221 DBG( 5 ) setColorAt( x, y, 0, 255, 0 ); 222 return true; 223 } 224 } 225 return false; 226 } 227 } 228 229 /******************************************************************************/ 230 makeRectHole(const Sint32 sx,const Sint32 sy,const Sint32 width,const Sint32 height,const Flag mask)231 void makeRectHole( const Sint32 sx, const Sint32 sy, const Sint32 width, 232 const Sint32 height, const Flag mask ) { 233 for( int y = sy; y < sy + height; y++ ) 234 for( int x = sx; x < sx + width; x++ ) 235 destroyEarthPixelClip( x, y, mask ); 236 } 237 238 /******************************************************************************/ 239 makeHole(const Sint32 xc,const Sint32 yc,const Sint32 size,const Flag mask)240 void makeHole( const Sint32 xc, const Sint32 yc, 241 const Sint32 size, const Flag mask ) { 242 Sint32 x = 0; 243 Sint32 y = size; 244 real d = 1.25 - static_cast<real>( size ); 245 246 Sint32 i; 247 for ( i = -x; i <= x; i++ ) { 248 destroyEarthPixelClip( xc + i, yc + y, mask ); 249 destroyEarthPixelClip( xc + i, yc - y, mask ); 250 } 251 for ( i = -y; i <= y; i++ ) { 252 destroyEarthPixelClip( xc + i, yc + x, mask ); 253 destroyEarthPixelClip( xc + i, yc - x, mask ); 254 } 255 256 while ( y > x ) { 257 x++; 258 if ( d > 0 ) { 259 y--; 260 d += 2.0 * (x - y); 261 } 262 else { 263 d += 2.0 * x + 1.0; 264 } 265 266 for ( i = -x; i <= x; i++ ) { 267 destroyEarthPixelClip( xc + i, yc + y, mask ); 268 destroyEarthPixelClip( xc + i, yc - y, mask ); 269 } 270 for ( i = -y; i <= y; i++ ) { 271 destroyEarthPixelClip( xc + i, yc + x, mask ); 272 destroyEarthPixelClip( xc + i, yc - x, mask ); 273 } 274 } 275 } 276 277 /******************************************************************************/ 278 setSpecialEarth(const Uint32 x,const Uint32 y,const Flag flag)279 void setSpecialEarth( const Uint32 x, const Uint32 y, 280 const Flag flag ) { 281 // check clipping 282 if( x >= m_sizeX || y >= m_sizeY ) return; 283 284 real brightness; 285 int r, g, b; 286 287 if( flag & Flags::INDESTRUCTIBLE ) { 288 brightness = 0.5 + 0.2*localRnd.getNormedReal(); 289 r = g = b = static_cast<int>( 0x9c * brightness ); 290 } 291 else if( flag & Flags::UNDIGGABLE ) { 292 brightness = 0.5 + 0.2*localRnd.getNormedReal(); 293 r = static_cast<int>( 0x9c * brightness ), 294 g = static_cast<int>( 0x5a * brightness ), 295 b = static_cast<int>( 0x31 * brightness ); 296 } else { 297 brightness = 0.7 + 0.3*localRnd.getNormedReal(); 298 r = static_cast<int>( 0x9c * brightness ); 299 g = static_cast<int>( 0x5a * brightness ); 300 b = static_cast<int>( 0x31 * brightness ); 301 } 302 303 setColorAt( x, y, r, g, b ); 304 m_flags.getReferenceTo( x, y ) = flag; 305 } 306 307 /******************************************************************************/ 308 makeStone(const Sint32 xc,const Sint32 yc,const Sint32 size,const Flag flag,const Flag mask)309 void makeStone( const Sint32 xc, const Sint32 yc, const Sint32 size, 310 const Flag flag, const Flag mask ) { 311 Sint32 x = 0; 312 Sint32 y = size; 313 real d = 1.25 - static_cast<real>( size ); 314 315 Sint32 i; 316 for ( i = -x; i <= x; i++ ) { 317 if( testPassableClip( xc + i, yc + y, mask )) setSpecialEarth( xc + i, yc + y, flag ); 318 if( testPassableClip( xc + i, yc - y, mask )) setSpecialEarth( xc + i, yc - y, flag ); 319 } 320 for ( i = -y; i <= y; i++ ) { 321 if( testPassableClip( xc + i, yc + x, mask )) setSpecialEarth( xc + i, yc + x, flag ); 322 if( testPassableClip( xc + i, yc - x, mask )) setSpecialEarth( xc + i, yc - x, flag ); 323 } 324 325 while ( y > x ) { 326 x++; 327 if ( d > 0 ) { 328 y--; 329 d += 2.0 * (x - y); 330 } 331 else { 332 d += 2.0 * x + 1.0; 333 } 334 335 for ( i = -x; i <= x; i++ ) { 336 if( testPassableClip( xc + i, yc + y, mask )) setSpecialEarth( xc + i, yc + y, flag ); 337 if( testPassableClip( xc + i, yc - y, mask )) setSpecialEarth( xc + i, yc - y, flag ); 338 } 339 for ( i = -y; i <= y; i++ ) { 340 if( testPassableClip( xc + i, yc + x, mask )) setSpecialEarth( xc + i, yc + x, flag ); 341 if( testPassableClip( xc + i, yc - x, mask )) setSpecialEarth( xc + i, yc - x, flag ); 342 } 343 } 344 } 345 346 /******************************************************************************/ 347 calculateBounceAngle(const real dx,const real dy,const int cx,const int cy,const Flag mask)348 real calculateBounceAngle( const real dx, const real dy, 349 const int cx, const int cy, const Flag mask ) { 350 static const int dxTest[8] = { 0, 1, 1, 1, 0, -1, -1, -1}, 351 dyTest[8] = {-1, -1, 0, 1, 1, 1, 0, -1}; 352 const real incomingAngle = ATAN2_REAL( dy, dx ); 353 int incomingDir = static_cast<int>( 8*incomingAngle/(2*M_PI) + 6.5 ) % 8; 354 355 if( ! testPassableSmoothing( cx + dxTest[incomingDir], 356 cy + dyTest[incomingDir], mask ) ) { 357 incomingDir = (incomingDir + 1) % 8; 358 if( ! testPassableSmoothing( cx + dxTest[incomingDir], 359 cy + dyTest[incomingDir], mask ) ) { 360 incomingDir = (incomingDir + 6) % 8; 361 if( ! testPassableSmoothing( cx + dxTest[incomingDir], 362 cy + dyTest[incomingDir], mask ) ) { 363 incomingDir = (incomingDir + 1) % 8; 364 } 365 } 366 } 367 368 int cwTest = (incomingDir+1) % 8, ccwTest = (incomingDir+7) % 8; 369 370 LOG( 5 ) 371 INFO( "Map::calculateBounceAngle:\n%c%c%c\n%c%c%c\n%c%c%c\n", 372 (testPassableSmoothing( cx - 1, cy - 1, mask ) ? '.' : '#'), 373 (testPassableSmoothing( cx , cy - 1, mask ) ? '.' : '#'), 374 (testPassableSmoothing( cx + 1, cy - 1, mask ) ? '.' : '#'), 375 (testPassableSmoothing( cx - 1, cy , mask ) ? '.' : '#'), 376 (testPassableSmoothing( cx , cy , mask ) ? '.' : '#'), 377 (testPassableSmoothing( cx + 1, cy , mask ) ? '.' : '#'), 378 (testPassableSmoothing( cx - 1, cy + 1, mask ) ? '.' : '#'), 379 (testPassableSmoothing( cx , cy + 1, mask ) ? '.' : '#'), 380 (testPassableSmoothing( cx + 1, cy + 1, mask ) ? '.' : '#') ); 381 382 // look for obstacles in clockwise direction 383 while( testPassableSmoothing( cx + dxTest[cwTest], cy + dyTest[cwTest], mask ) 384 && cwTest != incomingDir ) 385 cwTest = (cwTest+1) % 8; 386 387 // look for obstacles in counter-clockwise direction 388 while( testPassableSmoothing( cx + dxTest[ccwTest], cy + dyTest[ccwTest], mask ) 389 && ccwTest != incomingDir ) 390 ccwTest = (ccwTest+7) % 8; 391 392 LOG( 5 ) INFO( "incomingDir: %i; cwTest: %i; ccwTest: %i\n", 393 incomingDir, cwTest, ccwTest ); 394 395 /* 396 if( (ccwTest-cwTest+8) % 8 <= 2 ) { 397 return -incomingAngle; 398 } 399 else { 400 */ 401 return -incomingAngle + (M_PI*45.0/180.0)*(cwTest+ccwTest); 402 //} 403 } 404 405 /******************************************************************************/ 406 testCollRect(const int px,const int py,const int width,const int height,int & cx,int & cy)407 bool testCollRect( const int px, const int py, 408 const int width, const int height, 409 int& cx, int& cy ) { 410 LOG( 5 ) INFO( "Map::testCollRect: px: %3i; py: %3i; width: %3i; height: %3i\n", 411 px, py, width, height ); 412 413 for( int x = px; x < px+width; x++ ) { 414 //m_pixels.setValueAt( x, py, 0xffff00 ); 415 if( ! testPassableSmoothing( x, py, Flags::OBSTACLE_EARTH | Flags::OBSTACLE_OBJECT ) ) { 416 cx = x; cy = py; 417 LOG( 5 ) INFO( "Acoll at %i, %i\n", cx, cy ); 418 DBG( 5 ) setColorAt( cx, cy, 0, 255, 0 ); 419 return false; 420 } 421 //m_pixels.setValueAt( x, py+height-1, 0xffff00 ); 422 if( ! testPassableSmoothing( x, py+height-1, Flags::OBSTACLE_EARTH | Flags::OBSTACLE_OBJECT ) ) { 423 cx = x; cy = py+height-1; 424 LOG( 5 ) INFO( "Bcoll at %i, %i\n", cx, cy ); 425 DBG( 5 ) setColorAt( cx, cy, 0, 255, 0 ); 426 return false; 427 } 428 } 429 430 for( int y = py+1; y < py+height-1; y++ ) { 431 //m_pixels.setValueAt( px , y, 0xffff00 ); 432 if( ! testPassableSmoothing( px, y, Flags::OBSTACLE_EARTH | Flags::OBSTACLE_OBJECT ) ) { 433 cx = px; cy = y; 434 LOG( 5 ) INFO( "Ccoll at %i, %i\n", cx, cy ); 435 DBG( 5 ) setColorAt( cx, cy, 0, 255, 0 ); 436 return false; 437 } 438 //m_pixels.setValueAt( px+width-1, y, 0xffff00 ); 439 if( ! testPassableSmoothing( px+width-1, y, Flags::OBSTACLE_EARTH | Flags::OBSTACLE_OBJECT ) ) { 440 cx = px+width-1; cy = y; 441 LOG( 5 ) INFO( "Dcoll at %i, %i\n", cx, cy ); 442 DBG( 5 ) setColorAt( cx, cy, 0, 255, 0 ); 443 return false; 444 } 445 } 446 447 return true; 448 } 449 450 /******************************************************************************/ 451 testFilledCollRect(const int px,const int py,const int width,const int height)452 bool testFilledCollRect( const int px, const int py, 453 const int width, const int height ) { 454 LOG( 5 ) INFO( "Map::testFilledCollRect: px: %3i; py: %3i; width: %3i; height: %3i\n", 455 px, py, width, height ); 456 457 // check clipping 458 if( px < 0 || py < 0 || static_cast<Uint32>( px+width ) >= m_sizeX || 459 static_cast<Uint32>( py+height ) >= m_sizeY ) { 460 return false; 461 } 462 463 for( int y = py; y < py+height; y++ ) { 464 for( int x = px; x < px+width; x++ ) { 465 //m_pixels.setValueAt( x, py, 0xffff00 ); 466 if( ! testPassableSmoothing( x, y, Flags::OBSTACLE_EARTH | Flags::OBSTACLE_OBJECT ) ) { 467 return false; 468 } 469 } 470 } 471 472 return true; 473 } 474 475 /******************************************************************************/ 476 testFilledCollRectCollPos(const int px,const int py,const int width,const int height,int & cx,int & cy)477 bool testFilledCollRectCollPos( const int px, const int py, 478 const int width, const int height, 479 int& cx, int& cy ) { 480 LOG( 5 ) INFO( "Map::testFilledCollRect: px: %3i; py: %3i; width: %3i; height: %3i\n", 481 px, py, width, height ); 482 483 // check clipping 484 if( px < 0 || py < 0 || static_cast<Uint32>( px+width ) >= m_sizeX || 485 static_cast<Uint32>( py+height ) >= m_sizeY ) { 486 cx = cy = -1; 487 return false; 488 } 489 490 for( cy = py; cy < py+height; cy++ ) { 491 for( cx = px; cx < px+width; cx++ ) { 492 //m_pixels.setValueAt( x, py, 0xffff00 ); 493 if( ! testPassableSmoothing( cx, cy, Flags::OBSTACLE_EARTH | Flags::OBSTACLE_OBJECT ) ) { 494 return false; 495 } 496 } 497 } 498 499 return true; 500 } 501 502 /******************************************************************************/ 503 setCollRect(const int px,const int py,const int width,const int height)504 void setCollRect( const int px, const int py, 505 const int width, const int height ) { 506 LOG( 5 ) INFO( "Map::setCollRect: setting collision rectangle at (%i, %i, %i, %i)\n", 507 px, py, width, height ); 508 bool saveFlagsLater = false; 509 String comment; 510 DBG( 3 ) { 511 if( ! CHECK( testFilledCollRect( px, py, width, height ), 512 "Map::setCollRect: collRect not completely passable\n" ) ) { 513 comment.format( "Map::setCollRect: collRect( %i, %i, %i, %i ) not " 514 "completely passable", px, py, 515 width, height ); 516 saveFlagsLater = true; 517 } 518 } 519 520 int x, y; 521 for( y = py; y < py+height; y++ ) { 522 for( x = px; x < px+width; x++ ) { 523 m_flags.getReferenceTo( x, y ) |= Flags::OBSTACLE_OBJECT | Flags::UNABLE_ANY; 524 } 525 } 526 527 if( saveFlagsLater ) saveFlags( comment ); 528 } 529 530 /******************************************************************************/ 531 removeCollRect(const int px,const int py,const int width,const int height)532 void removeCollRect( const int px, const int py, 533 const int width, const int height ) { 534 int x, y; 535 for( y = py; y < py+height; y++ ) { 536 for( x = px; x < px+width; x++ ) { 537 m_flags.getReferenceTo( x, y ) &= ~(Flags::OBSTACLE_OBJECT | Flags::UNABLE_ANY); 538 } 539 } 540 } 541 542 /******************************************************************************/ 543 testLineCollRect(int x1,int y1,int x2,int y2,const int width,const int height,int & pcx,int & pcy,int & cx,int & cy)544 bool testLineCollRect( int x1, int y1, int x2, int y2, 545 const int width, const int height, 546 int& pcx, int& pcy, int& cx, int& cy ) { 547 int i; 548 int sx, sy; // step positive or negative (1 or -1) 549 int dx, dy; // delta (difference in X and Y between points) 550 int e; 551 552 LOG( 5 ) INFO( "Map::testLineCollRect: x1: %3i; y1: %3i; x2: %3i; y2: %3i; width: %3i; height: %3i\n", 553 x1, y1, x2, y2, width, height ); 554 dx = abs( x2 - x1 ); 555 sx = (x2 - x1 > 0) ? 1 : -1; 556 dy = abs( y2 - y1 ); 557 sy = (y2 - y1 > 0) ? 1 : -1; 558 559 cx = pcx = x1; cy = pcy = y1; 560 561 if( dy <= dx ) { 562 e = (dy << 1) - dx; 563 for( i = 0; i <= dx; i++ ) { 564 if( ! testCollRect( x1, y1, width, height, cx, cy ) ) { 565 DBG( 3 ) CHECK( ! (pcx == cx && pcy == cy && &pcx != &cx), "Map::testLineCollRect: " 566 "precollision coords == collision coords (A) " 567 "(%i, %i) -> (%i, %i) preColl: (%i, %i), coll: " 568 "(%i, %i)\n", x1, y1, x2, y2, pcx, pcy, cx, cy ); 569 return false; 570 } 571 else { pcx = x1; pcy = y1; } 572 573 if( e >= 0 ) { 574 y1 += sy; e -= (dx << 1); 575 } 576 x1 += sx; e += (dy << 1); 577 } 578 } 579 else { 580 #define SWAP(a,b) {int tmpswap = a; a = b; b = tmpswap;} 581 SWAP(x1, y1); SWAP(dx, dy); SWAP(sx, sy); 582 #undef SWAP 583 e = (dy << 1) - dx; 584 for( i = 0; i <= dx; i++ ) { 585 if( ! testCollRect( y1, x1, width, height, cx, cy ) ) { 586 DBG( 3 ) CHECK( ! (pcx == cx && pcy == cy && &pcx != &cx), "Map::testLineCollRect: " 587 "precollision coords == collision coords (B) " 588 "(%i, %i) -> (%i, %i) preColl: (%i, %i), coll: " 589 "(%i, %i)\n", y1, x1, x2, y2, pcx, pcy, cx, cy ); 590 return false; 591 } 592 else { pcx = y1; pcy = x1; } 593 594 if( e >= 0 ) { 595 y1 += sy; e -= (dx << 1); 596 } 597 x1 += sx; e += (dy << 1); 598 } 599 } 600 601 return true; 602 } 603 604 /******************************************************************************/ 605 testLinePassable(int x1,int y1,int x2,int y2,int & pcx,int & pcy,int & cx,int & cy,const Flag mask)606 bool testLinePassable( int x1, int y1, int x2, int y2, 607 int& pcx, int& pcy, int& cx, int& cy, 608 const Flag mask ) { 609 int i; 610 int sx, sy; // step positive or negative (1 or -1) 611 int dx, dy; // delta (difference in X and Y between points) 612 int e; 613 614 dx = abs( x2 - x1 ); 615 sx = (x2 - x1 > 0) ? 1 : -1; 616 dy = abs( y2 - y1 ); 617 sy = (y2 - y1 > 0) ? 1 : -1; 618 619 cx = pcx = x1; cy = pcy = y1; 620 621 if( dy <= dx ) { 622 e = (dy << 1) - dx; 623 for( i = 0; i <= dx; i++ ) { 624 if( ! testPassable( x1, y1, mask ) ) { 625 cx = x1; cy = y1; 626 DBG( 5 ) CHECK( ! (pcx == cx && pcy == cy && &pcx != &cx), "Map::testLinePassable: " 627 "precollision coords == collision coords (A) " 628 "(%i, %i) -> (%i, %i) preColl: (%i, %i), coll: " 629 "(%i, %i)\n", x1, y1, x2, y2, pcx, pcy, cx, cy ); 630 return false; 631 } 632 else { pcx = x1; pcy = y1; } 633 634 if( e >= 0 ) { 635 y1 += sy; e -= (dx << 1); 636 } 637 x1 += sx; e += (dy << 1); 638 } 639 } 640 else { 641 #define SWAP(a,b) {int tmpswap = a; a = b; b = tmpswap;} 642 SWAP(x1, y1); SWAP(dx, dy); SWAP(sx, sy); 643 #undef SWAP 644 e = (dy << 1) - dx; 645 for( i = 0; i <= dx; i++ ) { 646 if( ! testPassable( y1, x1, mask ) ) { 647 cx = y1; cy = x1; 648 DBG( 5 ) CHECK( ! (pcx == cx && pcy == cy && &pcx != &cx), "Map::testLinePassable: " 649 "precollision coords == collision coords (B) " 650 "(%i, %i) -> (%i, %i) preColl: (%i, %i), coll: " 651 "(%i, %i)\n", y1, x1, x2, y2, pcx, pcy, cx, cy ); 652 return false; 653 } 654 else { pcx = y1; pcy = x1; } 655 656 if( e >= 0 ) { 657 y1 += sy; e -= (dx << 1); 658 } 659 x1 += sx; e += (dy << 1); 660 } 661 } 662 663 return true; 664 } 665 666 /******************************************************************************/ 667 testLinePassableSmoothing(int x1,int y1,int x2,int y2,int & pcx,int & pcy,int & cx,int & cy,const Flag mask)668 bool testLinePassableSmoothing( int x1, int y1, int x2, int y2, 669 int& pcx, int& pcy, int& cx, int& cy, 670 const Flag mask ) { 671 int i; 672 int sx, sy; // step positive or negative (1 or -1) 673 int dx, dy; // delta (difference in X and Y between points) 674 int e; 675 676 dx = abs( x2 - x1 ); 677 sx = (x2 - x1 > 0) ? 1 : -1; 678 dy = abs( y2 - y1 ); 679 sy = (y2 - y1 > 0) ? 1 : -1; 680 681 cx = pcx = x1; cy = pcy = y1; 682 683 if( dy <= dx ) { 684 e = (dy << 1) - dx; 685 for( i = 0; i <= dx; i++ ) { 686 if( ! testPassableSmoothing( x1, y1, mask ) ) { 687 cx = x1; cy = y1; 688 DBG( 5 ) CHECK( ! (pcx == cx && pcy == cy && &pcx != &cx), "Map::testLinePassableSmoothing: " 689 "precollision coords == collision coords (A) " 690 "(%i, %i) -> (%i, %i) preColl: (%i, %i), coll: " 691 "(%i, %i)\n", x1, y1, x2, y2, pcx, pcy, cx, cy ); 692 return false; 693 } 694 else { pcx = x1; pcy = y1; } 695 696 if( e >= 0 ) { 697 y1 += sy; e -= (dx << 1); 698 } 699 x1 += sx; e += (dy << 1); 700 } 701 } 702 else { 703 #define SWAP(a,b) {int tmpswap = a; a = b; b = tmpswap;} 704 SWAP(x1, y1); SWAP(dx, dy); SWAP(sx, sy); 705 #undef SWAP 706 e = (dy << 1) - dx; 707 for( i = 0; i <= dx; i++ ) { 708 if( ! testPassableSmoothing( y1, x1, mask ) ) { 709 cx = y1; cy = x1; 710 DBG( 5 ) CHECK( ! (pcx == cx && pcy == cy && &pcx != &cx), "Map::testLinePassableSmoothing: " 711 "precollision coords == collision coords (B) " 712 "(%i, %i) -> (%i, %i) preColl: (%i, %i), coll: " 713 "(%i, %i)\n", y1, x1, x2, y2, pcx, pcy, cx, cy ); 714 return false; 715 } 716 else { pcx = y1; pcy = x1; } 717 718 if( e >= 0 ) { 719 y1 += sy; e -= (dx << 1); 720 } 721 x1 += sx; e += (dy << 1); 722 } 723 } 724 725 return true; 726 } 727 728 /******************************************************************************/ 729 drawLine(int x1,int y1,int x2,int y2,const Uint32 col)730 void drawLine( int x1, int y1, int x2, int y2, const Uint32 col) { 731 int i; 732 int sx, sy; // step positive or negative (1 or -1) 733 int dx, dy; // delta (difference in X and Y between points) 734 int e; 735 736 dx = abs( x2 - x1 ); 737 sx = (x2 - x1 > 0) ? 1 : -1; 738 dy = abs( y2 - y1 ); 739 sy = (y2 - y1 > 0) ? 1 : -1; 740 741 if( dy <= dx ) { 742 e = (dy << 1) - dx; 743 for( i = 0; i <= dx; i++ ) { 744 setColorAt( x1, y1, col ); 745 746 if( e >= 0 ) { 747 y1 += sy; e -= (dx << 1); 748 } 749 x1 += sx; e += (dy << 1); 750 } 751 } 752 else { 753 #define SWAP(a,b) {int tmpswap = a; a = b; b = tmpswap;} 754 SWAP(x1, y1); SWAP(dx, dy); SWAP(sx, sy); 755 #undef SWAP 756 e = (dy << 1) - dx; 757 for( i = 0; i <= dx; i++ ) { 758 setColorAt( y1, x1, col ); 759 760 if( e >= 0 ) { 761 y1 += sy; e -= (dx << 1); 762 } 763 x1 += sx; e += (dy << 1); 764 } 765 } 766 } 767 768 }; 769 770 /******************************************************************************/ 771 /******************************************************************************/ 772 /******************************************************************************/ 773 774 class ServerMap : public Map, public Serializable { 775 private: 776 //! Storage for the foreground pixels 777 MapMemory<Uint32> m_pixels; 778 //! Default format for the map on the server 779 SDL_PixelFormat m_pixelFormat; 780 781 public: 782 //! Constructor ServerMap(int sizeX,int sizeY)783 ServerMap( int sizeX, int sizeY ) 784 : Map( sizeX, sizeY ), 785 m_pixels( sizeX, sizeY ) { 786 m_pixelFormat.palette = 0; 787 m_pixelFormat.BitsPerPixel = 32; 788 m_pixelFormat.BytesPerPixel = 4; 789 m_pixelFormat.Rmask = 0x000000ff; 790 m_pixelFormat.Gmask = 0x0000ff00; 791 m_pixelFormat.Bmask = 0x00ff0000; 792 m_pixelFormat.Amask = 0x00000000; 793 m_pixelFormat.Rshift = 0; 794 m_pixelFormat.Gshift = 8; 795 m_pixelFormat.Bshift = 16; 796 m_pixelFormat.Ashift = 24; 797 m_pixelFormat.Rloss = 0; 798 m_pixelFormat.Gloss = 0; 799 m_pixelFormat.Bloss = 0; 800 m_pixelFormat.Aloss = 0; 801 } 802 803 /******************************************************************************/ 804 805 // Destructor ~ServerMap()806 virtual ~ServerMap() { 807 LOG( 4 ) INFO( "ServerMap::~ServerMap: destructor called\n" ); 808 } 809 810 /******************************************************************************/ 811 812 // returns a pointer to the pixel container getPixels()813 MapMemory<Uint32>* getPixels() { 814 return &m_pixels; 815 } 816 817 /******************************************************************************/ 818 getPixelFormat() const819 const SDL_PixelFormat* getPixelFormat() const { 820 return &m_pixelFormat; 821 } 822 823 /******************************************************************************/ 824 getColorAt(const Uint32 x,const Uint32 y,Uint8 & red,Uint8 & green,Uint8 & blue)825 virtual void getColorAt( const Uint32 x, const Uint32 y, 826 Uint8& red, Uint8& green, Uint8& blue ) { 827 Uint32 pixel = m_pixels.getValueAt( x, y ); 828 SDL_GetRGB( pixel, &m_pixelFormat, &red, &green, &blue ); 829 } 830 831 /******************************************************************************/ 832 setColorAt(const Uint32 x,const Uint32 y,const Uint8 r,const Uint8 g,const Uint8 b)833 virtual void setColorAt( const Uint32 x, const Uint32 y, 834 const Uint8 r, const Uint8 g, const Uint8 b ) { 835 const Uint32 pixel = SDL_MapRGB( &m_pixelFormat, r, g, b ); 836 m_pixels.setValueAt( x, y, pixel ); 837 } 838 839 /******************************************************************************/ 840 setColorAt(const Uint32 x,const Uint32 y,const Uint32 color)841 virtual void setColorAt( const Uint32 x, const Uint32 y, const Uint32 color ) { 842 const Uint8 r = static_cast<Uint8>( color >> 16 ), 843 g = static_cast<Uint8>( color >> 8 ), 844 b = static_cast<Uint8>( color ); 845 const Uint32 pixel = SDL_MapRGB( &m_pixelFormat, r, g, b ); 846 m_pixels.setValueAt( x, y, pixel ); 847 } 848 849 /******************************************************************************/ 850 851 //! creates a map from a theme 852 // void createFromTheme( Theme& theme, World& world ); 853 //! fills the map with random circles 854 // void fillWithRandomCircles(); 855 //! places the passed sprite as map stuff of passed material 856 void placeMapStuffItem( const Sprite* const item, 857 const Sprite* const flags, 858 const Uint32 x, const Uint32 y, 859 const int material, 860 const bool smoothable = true ); 861 //! places the passed sprite as map stuff of passed material placeMapStuffItem(const Sprite * const item,const Uint32 x,const Uint32 y,const int material,const bool smoothable=true)862 void placeMapStuffItem( const Sprite* const item, 863 const Uint32 x, const Uint32 y, 864 const int material, 865 const bool smoothable = true ) { 866 placeMapStuffItem( item, item, x, y, material, smoothable ); 867 } 868 869 //! \name (de)serialization 870 //@{ 871 //! return the size of the serialized map getSerializeBufferSize() const872 virtual Uint32 getSerializeBufferSize() const { 873 return 2 * Serialize<Uint32>::sizeOf() + 874 m_pixels.getSerializeBufferSize() + 875 m_flags.getSerializeBufferSize(); 876 } 877 878 /*! \brief serialize the map into the buffer starting at 879 * bufferPointer. After this method bufferPointer points to 880 * next char after the last char of the serialization of the 881 * map. 882 */ 883 virtual void serialize( Uint8*& bufferPointer ) const; 884 885 /*! \brief create a new map out of a serialization in the buffer 886 * starting at bufferPointer. After this method bufferPointer 887 * points to next char after the last char of the serialization 888 * of the map. 889 */ 890 static ServerMap* createAndDeserialize( Uint8*& bufferPointer ); 891 892 /*! \brief replace the existing map by deserializing the contents 893 * of the buffer pointed to by bufferPointer. After this method 894 * bufferPointer points to next char after the last char of the 895 * serialization of the map. 896 */ 897 virtual void deserialize( Uint8*& bufferPointer ); 898 //@} 899 }; 900 901 /******************************************************************************/ 902 /******************************************************************************/ 903 /******************************************************************************/ 904 905 class ClientMap : public Map { 906 private: 907 //! Storage for the foreground pixels 908 SDL_Surface* m_pixels; 909 910 /******************************************************************************/ 911 912 public: 913 //! Constructor ClientMap(ServerMap & serverMap,SDL_PixelFormat * format,Uint32 flags)914 ClientMap( ServerMap& serverMap, SDL_PixelFormat* format, Uint32 flags ) 915 : Map( *serverMap.getFlags() ) { 916 LOG( 3 ) INFO( "ClientMap::ClientMap: Constructor called\n" ); 917 LOG( 4 ) INFO( "ClientMap::ClientMap: Create surface from server map data\n" ); 918 SDL_Surface* serverSurface = 919 SDL_CreateRGBSurfaceFrom( serverMap.getPixels()->getMemory(), 920 serverMap.getSizeX(), serverMap.getSizeY(), 921 serverMap.getPixelFormat()->BitsPerPixel, 922 serverMap.getPixelFormat()->BytesPerPixel * 923 serverMap.getSizeX(), 924 serverMap.getPixelFormat()->Rmask, 925 serverMap.getPixelFormat()->Gmask, 926 serverMap.getPixelFormat()->Bmask, 927 serverMap.getPixelFormat()->Amask ); 928 ASSERT( serverSurface, "ClientMap::ClientMap: could not create surface\n" ); 929 LOG( 4 ) INFO( "ClientMap::ClientMap: Converting server surface to client format\n" ); 930 m_pixels = SDL_ConvertSurface( serverSurface, format, flags ); 931 ASSERT( m_pixels, "ClientMap::ClientMap: could not convert surface\n" ); 932 LOG( 4 ) INFO( "ClientMap::ClientMap: Freeing server surface\n" ); 933 SDL_FreeSurface( serverSurface ); 934 } 935 936 /******************************************************************************/ 937 938 //! Copy constructor ClientMap(const ClientMap & m)939 ClientMap( const ClientMap& m ) : Map( m ) { 940 m_pixels = SDL_CreateRGBSurface 941 ( m.m_pixels->flags, m.m_pixels->w, m.m_pixels->h, 942 m.m_pixels->format->BitsPerPixel, 943 m.m_pixels->format->Rmask, 944 m.m_pixels->format->Gmask, 945 m.m_pixels->format->Bmask, 946 m.m_pixels->format->Amask ); 947 ASSERT( m_pixels, "ClientMap::ClientMap: could not create surface\n" ); 948 SDL_BlitSurface( m.m_pixels, 0, m_pixels, 0 ); 949 } 950 951 /******************************************************************************/ 952 953 // Destructor ~ClientMap()954 virtual ~ClientMap() { 955 LOG( 3 ) INFO( "ClientMap::~ClientMap: destructor called\n" ); 956 SDL_FreeSurface( m_pixels ); 957 } 958 getPixels()959 SDL_Surface* getPixels() { 960 return m_pixels; 961 } 962 963 /******************************************************************************/ 964 getColorAt(const Uint32 x,const Uint32 y,Uint8 & red,Uint8 & green,Uint8 & blue)965 virtual void getColorAt( const Uint32 x, const Uint32 y, 966 Uint8& red, Uint8& green, Uint8& blue ) { 967 Uint32 pixel = Graphics::getPixel( m_pixels, x, y ); 968 SDL_GetRGB( pixel, m_pixels->format, &red, &green, &blue ); 969 } 970 971 /******************************************************************************/ 972 setColorAt(const Uint32 x,const Uint32 y,const Uint8 r,const Uint8 g,const Uint8 b)973 virtual void setColorAt( const Uint32 x, const Uint32 y, 974 const Uint8 r, const Uint8 g, const Uint8 b ) { 975 const Uint32 pixel = SDL_MapRGB( m_pixels->format, r, g, b ); 976 Graphics::setPixel( m_pixels, x, y, pixel ); 977 } 978 979 /******************************************************************************/ 980 setColorAt(const Uint32 x,const Uint32 y,const Uint32 color)981 virtual void setColorAt( const Uint32 x, const Uint32 y, const Uint32 color ) { 982 const Uint8 r = static_cast<Uint8>( color >> 16 ), 983 g = static_cast<Uint8>( color >> 8 ), 984 b = static_cast<Uint8>( color ); 985 const Uint32 pixel = SDL_MapRGB( m_pixels->format, r, g, b ); 986 Graphics::setPixel( m_pixels, x, y, pixel ); 987 } 988 989 /******************************************************************************/ 990 991 //! \name (de)serialization 992 //@{ 993 //! return the size of the serialized map getSerializeBufferSize() const994 virtual Uint32 getSerializeBufferSize() const { 995 return 2 * Serialize<Uint32>::sizeOf() + 996 m_pixels->h * m_pixels->pitch + 997 m_flags.getSerializeBufferSize(); 998 } 999 1000 /*! \brief serialize the map into the buffer starting at 1001 * bufferPointer. After this method bufferPointer points to 1002 * next char after the last char of the serialization of the 1003 * map. 1004 */ 1005 virtual void serialize( Uint8*& bufferPointer ) const; 1006 1007 /*! \brief replace the existing map by deserializing the contents 1008 * of the buffer pointed to by bufferPointer. After this method 1009 * bufferPointer points to next char after the last char of the 1010 * serialization of the map. 1011 */ 1012 virtual void deserialize( Uint8*& bufferPointer ); 1013 //@} 1014 }; 1015 1016 #endif // _MAP_HPP_ 1017