00001
00002
00003
00004 #ifdef WIN32
00005 #pragma warning(disable : 4786 )
00006 #endif
00007
00008 #include "CSTileMap.h"
00009 #include "CSXMLHelper.h"
00010
00011 CSTileMapLoader CSTileMapLoader::INSTANCE;
00012 const char *CSTileMap::CLASS = "CSTileMap";
00013
00014 CSTileMap::CSTileMap(const std::string &filename)
00015 {
00016 static char *functionName="CSTileMap";
00017 LOG_ENTER
00018 CSTileMapData data;
00019 loadTileMapData(filename, data);
00020 initialize(data);
00021 LOG_EXIT
00022 }
00023
00024
00025 CSTileMap::CSTileMap(const CSTileMap &tileMap)
00026 {
00027 static char *functionName="CSTileMap";
00028 LOG_ENTER
00029 initialize();
00030 mId = strdup(tileMap.mId);
00031 LOG_EXIT
00032 }
00033
00034 void CSTileMap::initialize(void)
00035 {
00036 static char *functionName="initialize";
00037 LOG_ENTER
00038 mScaleDisplay = false;
00039 mR = -1;
00040 mG = -1;
00041 mB = -1;
00042 mFactor = 0;
00043 mIsChangeable = false;
00044 mWorldNo = 0;
00045 mScaledMap = 0;
00046 mIsSolid = false;
00047 mId = 0;
00048 mTileSet = 0;
00049 mMap = 0;
00050 mRows = 0;
00051 mHeight = 0;
00052 mWidth = 0;
00053 mIsBackground = false;
00054 mIsParallax = false;
00055 mDisplayWidth = 0;
00056 mDisplayHeight = 0;
00057 mDisplayParams.mXDisplayStart = 0;
00058 mDisplayParams.mYDisplayStart = 0;
00059 mDisplayParams.mXWorldStart = 0;
00060 mDisplayParams.mYWorldStart = 0;
00061 mDisplayParams.mXPos = 0;
00062 mDisplayParams.mYPos = 0;
00063 mActive = false;
00064 LOG_EXIT
00065 }
00066
00067 void CSTileMap::initialize(const CSTileMapData &data)
00068 {
00069 static char *functionName="initialize";
00070 LOG_ENTER
00071 int xPos = 0;
00072 int yPos = 0;
00073 mXSize = 0;
00074 mYSize = 0;
00075 initialize();
00076 mId = strdup(data.id);
00077 mIsChangeable = data.isChangebale;
00078
00079 mTileSet = CSTileSetLoader::INSTANCE.load(data.tileSet);
00080 mRows = new StringVector();
00081
00082 for (StringVector::iterator iter = data.rows->begin(); iter != data.rows->end(); iter++)
00083 {
00084 char *row = (char *) *iter;
00085 mRows->push_back(strdup(row));
00086 if (mXSize < strlen(row))
00087 {
00088 mXSize = strlen(row);
00089 }
00090
00091 mYSize++;
00092 }
00093
00094 mMap = (CSTile ***) new void *[mYSize];
00095
00096 iter = mRows->begin();
00097 for (int y=0; y< mYSize; y++)
00098 {
00099 char *row = (char *) *iter;
00100 mMap[y] = (CSTile **) new void* [mXSize];
00101 int yh = 0;
00102 xPos = 0;
00103 for (int x = 0; x < mXSize; x++)
00104 {
00105 if (x < strlen(row))
00106 {
00107 if (row[x] == 0)
00108 {
00109 LOG_EXIT
00110 SDLMain::shutdown((std::string)"TileMap includes characters not found in TileSet! ", 1);
00111 }
00112 mMap[y][x] = mTileSet->getTile(row[x]);
00113 mMap[y][x]->setChanged(true);
00114 mMap[y][x]->setX(xPos);
00115 mMap[y][x]->setY(yPos);
00116 mMap[y][x]->setMapPosition(x,y);
00117 xPos += mMap[y][x]->getWitdh();
00118 if (yh < mMap[y][x]->getHeight())
00119 {
00120 yh = mMap[y][x]->getHeight();
00121 }
00122 }
00123 else
00124 {
00125 mMap[y][x] = 0;
00126 }
00127 }
00128 yPos += yh;
00129 iter++;
00130 }
00131 mHeight = yPos;
00132 mWidth = xPos;
00133 mWorldHeight = mHeight;
00134 mWorldWidth = mWidth;
00135 if (!(mMap[0][0]->getAnimationState()->mPicture->isSolid()))
00136 {
00137 mMap[0][0]->getAnimationState()->mPicture->getRGB(mR,mB,mG);
00138 }
00139 LOG_EXIT
00140 }
00141
00142 void CSTileMap::setOffset(int offsetX, int offsetY)
00143 {
00144 static char *functionName="setOffset";
00145 LOG_ENTER
00146 mOffsetX = offsetX;
00147 mOffsetY = offsetY;
00148
00149 int xPos = 0;
00150 int yPos = 0;
00151
00152 for (int y=0; y< mYSize; y++)
00153 {
00154 int yh = 0;
00155 for (int x = 0; x < mXSize; x++)
00156 {
00157 if (mMap[y][x] != 0)
00158 {
00159 mMap[y][x]->setX(xPos + mOffsetX);
00160 mMap[y][x]->setY(yPos + mOffsetY);
00161 xPos += mMap[y][x]->getWitdh();
00162 if (yh < mMap[y][x]->getHeight())
00163 {
00164 yh = mMap[y][x]->getHeight();
00165 }
00166 }
00167 }
00168 yPos += yh;
00169 xPos = 0;
00170 }
00171 LOG_EXIT
00172 }
00173
00174 void CSTileMap::setSolid(bool b)
00175 {
00176 static char *functionName="setSolid";
00177 LOG_ENTER
00178 mIsSolid = b;
00179 mTileSet->setSolid(b);
00180 mR=mG=mB = -1;
00181 LOG_EXIT
00182 }
00183
00184 void CSTileMap::setSecPerFrame(float secPerFrame)
00185 {
00186 static char *functionName="setSecPerFrame";
00187 LOG_ENTER
00188 mTileSet->setSecPerFrame(secPerFrame);
00189 LOG_EXIT
00190 }
00191
00192 CSTileMap::~CSTileMap()
00193 {
00194 static char *functionName="~CSTileMap";
00195 LOG_ENTER
00196 if (mScaledMap != 0)
00197 {
00198 SDLMain::freeSurface(mScaledMap);
00199 mScaledMap = 0;
00200 }
00201
00202 if (mId != 0)
00203 {
00204 free(mId);
00205 mId = 0;
00206 }
00207 if (mTileSet != 0)
00208 {
00209
00210 mTileSet = 0;
00211 }
00212 if (mRows != 0)
00213 {
00214 for (StringVector::iterator iter = mRows->begin(); iter != mRows->end(); iter++)
00215 {
00216 char *help = (char *) *iter;
00217 free(help);
00218 }
00219 free(mRows);
00220 mRows = 0;
00221 }
00222
00223 for (int y=0; y< mYSize; y++)
00224 {
00225 for (int x = 0; x < mXSize; x++)
00226 {
00227 if (mMap[y][x] != 0)
00228 {
00229 delete mMap[y][x];
00230 }
00231 }
00232 delete[] mMap[y];
00233 }
00234 delete[] mMap;
00235 LOG_EXIT
00236 }
00237
00238
00239
00240
00241 void CSTileMap::setTile(unsigned int x, unsigned int y, char idChar)
00242 {
00243 static char *functionName="setTile";
00244 if (!mIsChangeable)
00245 {
00246 return;
00247 }
00248 if (mMap[y][x] != 0)
00249 {
00250 int xPos = mMap[y][x]->getX();
00251 int yPos = mMap[y][x]->getY();
00252 delete mMap[y][x];
00253 mMap[y][x] = mTileSet->getTile(idChar);
00254 mMap[y][x]->setChanged(true);
00255 mMap[y][x]->setX(xPos);
00256 mMap[y][x]->setY(yPos);
00257 mMap[y][x]->setMapPosition(x,y);
00258 }
00259 }
00260
00261
00262
00263
00264
00265
00266 void CSTileMap::setTile(unsigned int x, unsigned int y, CSTile *tile, bool center)
00267 {
00268 static char *functionName="setTile";
00269 if (!mIsChangeable)
00270 {
00271 return;
00272 }
00273 if (mMap[y][x] != 0)
00274 {
00275 int xPos;
00276 int yPos;
00277 if ((center) && (mTileSet->isOneSize()))
00278 {
00279 xPos = x * mTileSet->getTileXSize() + mOffsetX;
00280 yPos = y * mTileSet->getTileYSize() + mOffsetY;
00281
00282 int nh = tile->getHeight();
00283 int nw = tile->getWitdh();
00284 xPos += (mTileSet->getTileXSize()-nw)/2;
00285 yPos += (mTileSet->getTileYSize()-nh)/2;
00286 }
00287 else
00288 {
00289 xPos = mMap[y][x]->getX();
00290 yPos = mMap[y][x]->getY();
00291 }
00292 mMap[y][x] = tile;
00293 mMap[y][x]->setChanged(true);
00294 mMap[y][x]->setX(xPos);
00295 mMap[y][x]->setY(yPos);
00296 mMap[y][x]->setMapPosition(x,y);
00297 }
00298 }
00299
00300 CSTile *CSTileMap::getTileAtPixel(unsigned int tx, unsigned int ty)
00301 {
00302 static char *functionName="getTileAtPixel";
00303 int x, y;
00304 CSTile *tile;
00305 for (y=0; y< mYSize; y++)
00306 {
00307 tile = mMap[y][0];
00308 if (ty > tile->getY() + tile->getHeight()) continue;
00309
00310 for (x = 0; x < mXSize; x++)
00311 {
00312 if (mMap[y][x] != 0)
00313 {
00314 tile = mMap[y][x];
00315 if (tx > tile->getX() + tile->getWitdh()) continue;
00316 return mMap[y][x];
00317 }
00318 }
00319 }
00320 return 0;
00321 }
00322
00323 CSTiles CSTileMap::getTouchingTiles(int tx,int ty, int tw, int th)
00324 {
00325 static char *functionName="getTouchingTiles";
00326
00327 CSTiles tiles;
00328 for (int y=0; y< mYSize; y++)
00329 {
00330
00331 CSTile *tile = mMap[y][0];
00332 int oY = tile->getY();
00333 int oH = tile->getHeight();
00334 if ((ty < oY) && (ty + th < oY))
00335 {
00336 return tiles;
00337 }
00338 if ((ty > oY) && (ty > oY + oH)) continue;
00339
00340 for (int x = 0; x < mXSize; x++)
00341 {
00342 if (mMap[y][x] != 0)
00343 {
00344 CSTile *tile = mMap[y][x];
00345 int oX = tile->getX();
00346 int oW = tile->getWitdh();
00347
00348 if ((tx < oX) && (tx + tw < oX)) break;
00349 if ((tx > oX) && (tx > oX + oW)) continue;
00350
00351 tiles.push_back(mMap[y][x]);
00352 }
00353 }
00354 }
00355 return tiles;
00356 }
00357
00358 void CSTileMap::display()
00359 {
00360 static char *functionName="display";
00361 int y,x;
00362 CSTile *tile;
00363
00364 for (y=sy; y< ey; y++)
00365 {
00366 for (x = sx; x < ex; x++)
00367 {
00368 tile = mMap[y][x];
00369 if (tile)
00370 {
00371 tile->display();
00372 }
00373 }
00374 }
00375 CSSprites::iterator iter = mSprites.begin();
00376 while (iter != mSprites.end())
00377 {
00378 CSSprite *sprite = *iter;
00379 if (mWorldNo == sprite->getWorldPos())
00380 {
00381 sprite->display();
00382 }
00383 iter++;
00384 }
00385 }
00386
00387 void CSTileMap::update()
00388 {
00389 static char *functionName="update";
00390 if (mActive)
00391 {
00392 int y,x;
00393 CSTile *tile;
00394 sx = 0;
00395 sy = 0;
00396 ex = mXSize;
00397 ey = mYSize;
00398 int startX = mDisplayParams.mXWorldStart;
00399 int startY = mDisplayParams.mYWorldStart;
00400 int endX = startX + mDisplayWidth;
00401 int endY = startY + mDisplayHeight;
00402
00403
00404 for (y = 0; ((y<mYSize) && (startY > (int) mMap[y][0]->getY()+(int)mMap[y][0]->getHeight())); y++);
00405 for (x = 0; ((x<mXSize) && (startX > (int) mMap[0][x]->getX()+(int)mMap[0][x]->getWitdh())); x++);
00406
00407 sx = x;
00408 sy = y;
00409
00410 for (; ((y<mYSize) && (endY > (int) mMap[y][0]->getY())); y++);
00411 for (; ((x<mXSize) && (endX > (int) mMap[0][x]->getX())); x++);
00412 ex = x;
00413 ey = y;
00414
00415 for (y=sy; y< ey; y++)
00416 {
00417 for (x = sx; x < ex; x++)
00418 {
00419 tile = mMap[y][x];
00420 if (tile)
00421 {
00422 tile->next(mDisplayParams);
00423 }
00424 }
00425 }
00426 }
00427 CSSprites::iterator iter = mSprites.begin();
00428 while (iter != mSprites.end())
00429 {
00430 CSSprite *sprite = *iter;
00431 if (mWorldNo == sprite->getWorldPos())
00432 {
00433 sprite->next();
00434 }
00435 iter++;
00436 }
00437 }
00438
00439 void CSTileMap::setMapPosition(int px, int py)
00440 {
00441 static char *functionName="setMapPosition";
00442 if (mIsBackground)
00443 {
00444 px = 0;
00445 py = 0;
00446 }
00447 else if (mIsParallax)
00448 {
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459 px = (float)(((float) mWidth-mDisplayWidth) * (float)((float)( ((float) px) / ((float)(mWorldWidth-mDisplayWidth)) )));
00460 py = (float)(((float) mHeight-mDisplayHeight) * (float)((float)( ((float) py) / ((float)(mWorldHeight-mDisplayHeight)) )));
00461 }
00462 mDisplayParams.mXWorldStart = px;
00463 mDisplayParams.mYWorldStart = py;
00464 }
00465
00466 void CSTileMap::setDisplayOffset(int xOffset, int yOffset)
00467 {
00468 static char *functionName="setDisplayOffset";
00469 mDisplayParams.mXDisplayStart = xOffset;
00470 mDisplayParams.mYDisplayStart = yOffset;
00471 CSSprites::iterator iter = mSprites.begin();
00472 while (iter != mSprites.end())
00473 {
00474 CSSprite *sprite = *iter;
00475 sprite->setDisplayOffset(xOffset, yOffset);
00476 iter++;
00477 }
00478 }
00479
00480 void CSTileMap::addSprite(CSSprite *sprite)
00481 {
00482 static char *functionName="addSprite";
00483 LOG_ENTER
00484
00485 removeSprite(sprite);
00486 mSprites.push_back(sprite);
00487 sprite->setDisplayOffset(mDisplayParams.mXDisplayStart, mDisplayParams.mYDisplayStart);
00488 LOG_EXIT
00489 }
00490
00491 void CSTileMap::removeSprite(CSSprite *sprite)
00492 {
00493 static char *functionName="removeSprite";
00494 LOG_ENTER
00495 CSSprites::iterator iter = mSprites.begin();
00496 while (iter != mSprites.end())
00497 {
00498 if ((*iter) == sprite)
00499 {
00500 mSprites.erase(iter);
00501 iter = mSprites.begin();
00502 }
00503 else
00504 {
00505 iter++;
00506 }
00507 }
00508 LOG_EXIT
00509 }
00510
00511 void CSTileMap::loadTileMapData(const std::string &filename, CSTileMapData &data)
00512 {
00513 static char *functionName="loadTileMapData";
00514 LOG_ENTER
00515 char tmp[10];
00516 CSXMLHelper xmlSupport(filename, "TILEMAP");
00517 try
00518 {
00519 if (xmlSupport.getError())
00520 {
00521 LOG_EXIT
00522 throw "error";
00523 }
00524
00525 data.id = strdup(xmlSupport.getString("ID").c_str());
00526 data.tileSet = strdup(xmlSupport.getString("SET").c_str());
00527
00528 data.isChangebale = xmlSupport.getInt("CHANGEABLE") != 0;
00529 int rowCount = xmlSupport.getInt("count(ROWS/ROW)");
00530 for (int i=0; i<rowCount; i++)
00531 {
00532
00533 std::string a = xmlSupport.getString((std::string)"ROWS/ROW["+itoa(i+1,tmp,10)+"]");
00534 data.rows->push_back(strdup(a.c_str()));
00535 }
00536 }
00537 catch(...)
00538 {
00539 LOG_EXIT
00540 SDLMain::shutdown((std::string)"XML error \"" + filename + "\": " + xmlSupport.getErrorMessage().c_str(), 1);
00541 }
00542 LOG_EXIT
00543 }
00544
00545 void CSTileMap::setBackground(bool b)
00546 {
00547 static char *functionName="setBackground";
00548 LOG_ENTER
00549 mIsBackground = b;
00550 LOG_EXIT
00551 }
00552
00553 void CSTileMap::scaleMapToFit(int width, int height)
00554 {
00555 static char *functionName="scaleMapToFit";
00556 LOG_ENTER
00557 mTileSet->scaleToFit(width, mXSize,height,mYSize);
00558 mHeight = height;
00559 mWidth = width;
00560 mWorldHeight = mHeight;
00561 mWorldWidth = mWidth;
00562 LOG_EXIT
00563 }
00564
00565 void CSTileMap::resetScaledMap()
00566 {
00567 static char *functionName="resetScaledMap";
00568 LOG_ENTER
00569 if (mScaledMap != 0)
00570 {
00571 SDLMain::freeSurface(mScaledMap);
00572 mScaledMap = 0;
00573 }
00574 for (int y=0; y< mYSize; y++)
00575 {
00576 int yh = 0;
00577 for (int x = 0; x < mXSize; x++)
00578 {
00579 if (mMap[y][x] != 0)
00580 {
00581 mMap[y][x]->setChanged(true);
00582 }
00583 }
00584 }
00585 LOG_EXIT
00586 }
00587
00588
00589 SDL_Surface *CSTileMap::getScaledMap(double factor, bool isSolid)
00590 {
00591 static char *functionName="getScaledMap";
00592 if ((!mIsChangeable) && (mFactor == factor) && (mScaledMap != 0))
00593 {
00594 return mScaledMap;
00595 }
00596
00597 if (!((mFactor == factor) && (mScaledMap != 0)))
00598 {
00599 if (mScaledMap != 0)
00600 {
00601 SDLMain::freeSurface(mScaledMap);
00602 mScaledMap = 0;
00603 }
00604 int width = ((double) mWorldWidth)*factor;
00605 int height = ((double) mWorldHeight)*factor;
00606 int flags = SDLMain::getScreen()->flags;
00607
00608
00609 if ((flags & SDL_HWSURFACE) == SDL_HWSURFACE)
00610 {
00611 flags -= SDL_HWSURFACE;
00612 }
00613 mScaledMap = SDL_CreateRGBSurface(flags,
00614 width,
00615 height,
00616 SDLMain::getScreen()->format->BitsPerPixel,
00617 SDLMain::getScreen()->format->Rmask,
00618 SDLMain::getScreen()->format->Gmask,
00619 SDLMain::getScreen()->format->Bmask,
00620 SDLMain::getScreen()->format->Amask);
00621
00622 if ((!(mMap[0][0]->getAnimationState()->mPicture->isSolid())) && (!isSolid))
00623 {
00624 if (mR+mG+mB != -3)
00625 {
00626 int mColorKey = SDL_MapRGB(mScaledMap->format, mR, mG, mB);
00627 SDL_SetColorKey(mScaledMap, SDL_SRCCOLORKEY, mColorKey);
00628 }
00629 }
00630 }
00631 mFactor = factor;
00632
00633 SDL_Rect dstrect;
00634
00635 int y,x,h;
00636 int ox = (double)(((double)(mOffsetX))*factor);
00637 int oy = (double)(((double)(mOffsetY))*factor);
00638
00639 dstrect.y = oy;
00640 for (y=0; y< mYSize; y++)
00641 {
00642 dstrect.x = ox;
00643 h = 0;
00644 for (x = 0; x < mXSize; x++)
00645 {
00646 SDL_Surface *src = mMap[y][x]->getScaledTile(factor);
00647 dstrect.w = src->w;
00648 dstrect.h = src->h;
00649 if (dstrect.h > h)
00650 {
00651 h = dstrect.h;
00652 }
00653
00654
00655
00656
00657
00658 {
00659
00660 if (mR+mG+mB != -3)
00661 {
00662 int mColorKey = SDL_MapRGB(mScaledMap->format, mR, mG, mB);
00663 SDL_FillRect(mScaledMap, &dstrect, mColorKey);
00664 }
00665
00666 SDL_BlitSurface(src, 0, mScaledMap, &dstrect);
00667 }
00668 dstrect.x += dstrect.w;
00669 }
00670 dstrect.y += h;
00671 }
00672 return mScaledMap;
00673 }
00674
00675 void CSTileMap::addScaledSprites(double factor, const SDL_Rect &offsetRect, SDL_Surface *destination, const SDL_Rect &displayRect)
00676 {
00677 static char *functionName="addScaledSprites";
00678 CSSprites::iterator iter = mSprites.begin();
00679 SDL_Rect dstrect;
00680 while (iter != mSprites.end())
00681 {
00682 CSSprite *sprite = *iter;
00683 if (mWorldNo == sprite->getWorldPos())
00684 {
00685 SDL_Surface *src = sprite->getScaledSprite(factor);
00686 register int x = sprite->getState().mActionState.mAnimationState.mDisplayParams.mXPos;
00687 register int y = sprite->getState().mActionState.mAnimationState.mDisplayParams.mYPos;
00688 dstrect.x = - offsetRect.x + displayRect.x + (double)(((double)(x))*factor);
00689 dstrect.y = - offsetRect.y + displayRect.y + (double)(((double)(y))*factor);
00690 dstrect.w = src->w;
00691 dstrect.h = src->h;
00692
00693 SDL_BlitSurface(src, 0, destination, &dstrect);
00694 }
00695 iter++;
00696 }
00697 }
00698