mirror of
https://github.com/vcmi/vcmi.git
synced 2025-06-04 23:17:41 +02:00
Support for fading heroes/boats (+flags);
Disabled map movement requests during fade;
This commit is contained in:
parent
3c3fb0e21d
commit
cbb75d1c7a
@ -671,12 +671,6 @@ void CMapHandler::CMapWorldViewBlitter::drawTileOverlay(SDL_Surface * targetSurf
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMapHandler::CMapWorldViewBlitter::drawNormalObject(SDL_Surface * targetSurf, SDL_Surface * sourceSurf, SDL_Rect * sourceRect) const
|
|
||||||
{
|
|
||||||
Rect scaledSourceRect(sourceRect->x * info->scale, sourceRect->y * info->scale, tileSize, tileSize);
|
|
||||||
CMapBlitter::drawNormalObject(targetSurf, sourceSurf, &scaledSourceRect);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CMapHandler::CMapWorldViewBlitter::drawHeroFlag(SDL_Surface * targetSurf, SDL_Surface * sourceSurf, SDL_Rect * sourceRect, SDL_Rect * destRect, bool moving) const
|
void CMapHandler::CMapWorldViewBlitter::drawHeroFlag(SDL_Surface * targetSurf, SDL_Surface * sourceSurf, SDL_Rect * sourceRect, SDL_Rect * destRect, bool moving) const
|
||||||
{
|
{
|
||||||
if (moving)
|
if (moving)
|
||||||
@ -685,13 +679,13 @@ void CMapHandler::CMapWorldViewBlitter::drawHeroFlag(SDL_Surface * targetSurf, S
|
|||||||
CMapBlitter::drawHeroFlag(targetSurf, sourceSurf, sourceRect, destRect, false);
|
CMapBlitter::drawHeroFlag(targetSurf, sourceSurf, sourceRect, destRect, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMapHandler::CMapWorldViewBlitter::drawHero(SDL_Surface * targetSurf, SDL_Surface * sourceSurf, SDL_Rect * sourceRect, bool moving) const
|
void CMapHandler::CMapWorldViewBlitter::drawObject(SDL_Surface * targetSurf, SDL_Surface * sourceSurf, SDL_Rect * sourceRect, bool moving) const
|
||||||
{
|
{
|
||||||
if (moving)
|
if (moving)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Rect scaledSourceRect(sourceRect->x * info->scale, sourceRect->y * info->scale, sourceRect->w, sourceRect->h);
|
Rect scaledSourceRect(sourceRect->x * info->scale, sourceRect->y * info->scale, sourceRect->w, sourceRect->h);
|
||||||
CMapBlitter::drawHero(targetSurf, sourceSurf, &scaledSourceRect, false);
|
CMapBlitter::drawObject(targetSurf, sourceSurf, &scaledSourceRect, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMapHandler::CMapBlitter::drawTileTerrain(SDL_Surface * targetSurf, const TerrainTile & tinfo, const TerrainTile2 & tile) const
|
void CMapHandler::CMapBlitter::drawTileTerrain(SDL_Surface * targetSurf, const TerrainTile & tinfo, const TerrainTile2 & tile) const
|
||||||
@ -791,21 +785,15 @@ void CMapHandler::CMapBlitter::drawFrame(SDL_Surface * targetSurf) const
|
|||||||
drawElement(EMapCacheType::FRAME, parent->ttiles[pos.x][pos.y][topTile.z].terbitmap, nullptr, targetSurf, &destRect);
|
drawElement(EMapCacheType::FRAME, parent->ttiles[pos.x][pos.y][topTile.z].terbitmap, nullptr, targetSurf, &destRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMapHandler::CMapBlitter::drawNormalObject(SDL_Surface * targetSurf, SDL_Surface * sourceSurf, SDL_Rect * sourceRect) const
|
|
||||||
{
|
|
||||||
Rect destRect(realTileRect);
|
|
||||||
drawElement(EMapCacheType::OBJECTS, sourceSurf, sourceRect, targetSurf, &destRect, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CMapHandler::CMapBlitter::drawHeroFlag(SDL_Surface * targetSurf, SDL_Surface * sourceSurf, SDL_Rect * sourceRect, SDL_Rect * destRect, bool moving) const
|
void CMapHandler::CMapBlitter::drawHeroFlag(SDL_Surface * targetSurf, SDL_Surface * sourceSurf, SDL_Rect * sourceRect, SDL_Rect * destRect, bool moving) const
|
||||||
{
|
{
|
||||||
drawElement(EMapCacheType::HERO_FLAGS, sourceSurf, sourceRect, targetSurf, destRect, true);
|
drawElement(EMapCacheType::HERO_FLAGS, sourceSurf, sourceRect, targetSurf, destRect, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMapHandler::CMapBlitter::drawHero(SDL_Surface * targetSurf, SDL_Surface * sourceSurf, SDL_Rect * sourceRect, bool moving) const
|
void CMapHandler::CMapBlitter::drawObject(SDL_Surface * targetSurf, SDL_Surface * sourceSurf, SDL_Rect * sourceRect, bool moving) const
|
||||||
{
|
{
|
||||||
Rect dstRect(realTileRect);
|
Rect dstRect(realTileRect);
|
||||||
drawElement(EMapCacheType::HEROES, sourceSurf, sourceRect, targetSurf, &dstRect, true);
|
drawElement(EMapCacheType::OBJECTS, sourceSurf, sourceRect, targetSurf, &dstRect, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMapHandler::CMapBlitter::drawObjects(SDL_Surface * targetSurf, const TerrainTile2 & tile) const
|
void CMapHandler::CMapBlitter::drawObjects(SDL_Surface * targetSurf, const TerrainTile2 & tile) const
|
||||||
@ -814,19 +802,14 @@ void CMapHandler::CMapBlitter::drawObjects(SDL_Surface * targetSurf, const Terra
|
|||||||
for(auto & object : objects)
|
for(auto & object : objects)
|
||||||
{
|
{
|
||||||
if (object.fadeAnimKey >= 0)
|
if (object.fadeAnimKey >= 0)
|
||||||
{
|
{
|
||||||
// TODO fading heroes/boats will not be drawn correctly this way
|
|
||||||
|
|
||||||
auto fadeIter = parent->fadeAnims.find(object.fadeAnimKey);
|
auto fadeIter = parent->fadeAnims.find(object.fadeAnimKey);
|
||||||
if (fadeIter != parent->fadeAnims.end())
|
if (fadeIter != parent->fadeAnims.end())
|
||||||
{
|
{
|
||||||
// this object is currently fading, so skip normal drawing
|
// this object is currently fading, so skip normal drawing
|
||||||
Rect r1(object.rect);
|
|
||||||
r1.w = tileSize;
|
|
||||||
r1.h = tileSize;
|
|
||||||
Rect r2(realTileRect);
|
Rect r2(realTileRect);
|
||||||
CFadeAnimation * fade = (*fadeIter).second.second;
|
CFadeAnimation * fade = (*fadeIter).second.second;
|
||||||
fade->draw(targetSurf, &r1, &r2);
|
fade->draw(targetSurf, nullptr, &r2);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -839,124 +822,28 @@ void CMapHandler::CMapBlitter::drawObjects(SDL_Surface * targetSurf, const Terra
|
|||||||
|
|
||||||
if (!canDrawObject(obj))
|
if (!canDrawObject(obj))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
PlayerColor color = obj->tempOwner;
|
|
||||||
|
|
||||||
SDL_Rect pp = object.rect;
|
|
||||||
pp.h = tileSize;
|
|
||||||
pp.w = tileSize;
|
|
||||||
|
|
||||||
const CGHeroInstance * hero = (obj->ID != Obj::HERO
|
|
||||||
? nullptr
|
|
||||||
: static_cast<const CGHeroInstance*>(obj));
|
|
||||||
|
|
||||||
// this block probably could be changed into templated methods for heroes/boats/other objects;
|
|
||||||
|
|
||||||
//print hero / boat and flag
|
auto objData = findObjectBitmap(obj, info->anim);
|
||||||
if((hero && hero->moveDir && hero->type) || (obj->ID == Obj::BOAT)) //it's hero or boat
|
if (objData.objBitmap)
|
||||||
{
|
{
|
||||||
const int IMGVAL = 8; //frames per group of movement animation
|
Rect srcRect(object.rect.x, object.rect.y, tileSize, tileSize);
|
||||||
ui8 dir;
|
|
||||||
std::vector<Cimage> * iv = nullptr;
|
drawObject(targetSurf, objData.objBitmap, &srcRect, objData.isMoving);
|
||||||
std::vector<CDefEssential *> Graphics::*flg = nullptr;
|
if (objData.flagBitmap)
|
||||||
SDL_Surface * tb = nullptr; //surface to blitted
|
|
||||||
|
|
||||||
if(hero) //hero
|
|
||||||
{
|
{
|
||||||
if(hero->tempOwner >= PlayerColor::PLAYER_LIMIT) //Neutral hero?
|
if (objData.isMoving)
|
||||||
{
|
{
|
||||||
logGlobal->errorStream() << "A neutral hero (" << hero->name << ") at " << hero->pos << ". Should not happen!";
|
srcRect.y += FRAMES_PER_MOVE_ANIM_GROUP * 2 - tileSize;
|
||||||
continue;
|
Rect dstRect(realPos.x, realPos.y - tileSize / 2, tileSize, tileSize);
|
||||||
|
drawHeroFlag(targetSurf, objData.flagBitmap, &srcRect, &dstRect, true);
|
||||||
}
|
}
|
||||||
|
else if (obj->pos.x == pos.x && obj->pos.y == pos.y)
|
||||||
dir = hero->moveDir;
|
|
||||||
|
|
||||||
//pick graphics of hero (or boat if hero is sailing)
|
|
||||||
if (hero->boat)
|
|
||||||
iv = &graphics->boatAnims[hero->boat->subID]->ourImages;
|
|
||||||
else
|
|
||||||
iv = &graphics->heroAnims[hero->appearance.animationFile]->ourImages;
|
|
||||||
|
|
||||||
//pick appropriate flag set
|
|
||||||
if(hero->boat)
|
|
||||||
{
|
|
||||||
switch (hero->boat->subID)
|
|
||||||
{
|
|
||||||
case 0: flg = &Graphics::flags1; break;
|
|
||||||
case 1: flg = &Graphics::flags2; break;
|
|
||||||
case 2: flg = &Graphics::flags3; break;
|
|
||||||
default: logGlobal->errorStream() << "Not supported boat subtype: " << hero->boat->subID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
flg = &Graphics::flags4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else //boat
|
|
||||||
{
|
|
||||||
const CGBoat *boat = static_cast<const CGBoat*>(obj);
|
|
||||||
dir = boat->direction;
|
|
||||||
iv = &graphics->boatAnims[boat->subID]->ourImages;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(hero && !hero->isStanding) //hero is moving
|
|
||||||
{
|
|
||||||
size_t gg;
|
|
||||||
for(gg=0; gg<iv->size(); ++gg)
|
|
||||||
{
|
|
||||||
if((*iv)[gg].groupNumber == getHeroFrameNum(dir, true))
|
|
||||||
{
|
|
||||||
tb = (*iv)[gg+info->getHeroAnim()%IMGVAL].bitmap;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
drawHero(targetSurf, tb, &pp, true);
|
|
||||||
|
|
||||||
pp.y += IMGVAL * 2 - tileSize;
|
|
||||||
Rect destRect(realPos.x, realPos.y - tileSize / 2, tileSize, tileSize);
|
|
||||||
drawHeroFlag(targetSurf, (graphics->*flg)[color.getNum()]->ourImages[gg + info->getHeroAnim() % IMGVAL + 35].bitmap, &pp, &destRect, true);
|
|
||||||
|
|
||||||
}
|
|
||||||
else //hero / boat stands still
|
|
||||||
{
|
|
||||||
size_t gg;
|
|
||||||
for(gg=0; gg < iv->size(); ++gg)
|
|
||||||
{
|
|
||||||
if((*iv)[gg].groupNumber == getHeroFrameNum(dir, false))
|
|
||||||
{
|
|
||||||
tb = (*iv)[gg].bitmap;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
drawHero(targetSurf, tb, &pp, false);
|
|
||||||
|
|
||||||
//printing flag
|
|
||||||
if(flg
|
|
||||||
&& obj->pos.x == pos.x
|
|
||||||
&& obj->pos.y == pos.y)
|
|
||||||
{
|
{
|
||||||
Rect dstRect(realPos.x - 2 * tileSize, realPos.y - tileSize, 3 * tileSize, 2 * tileSize);
|
Rect dstRect(realPos.x - 2 * tileSize, realPos.y - tileSize, 3 * tileSize, 2 * tileSize);
|
||||||
if (dstRect.x - info->drawBounds->x > -tileSize * 2)
|
drawHeroFlag(targetSurf, objData.flagBitmap, nullptr, &dstRect, false);
|
||||||
{
|
|
||||||
auto surf = (graphics->*flg)[color.getNum()]->ourImages
|
|
||||||
[getHeroFrameNum(dir, false) * 8 + (info->getHeroAnim() / 4) % IMGVAL].bitmap;
|
|
||||||
drawHeroFlag(targetSurf, surf, nullptr, &dstRect, false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else //blit normal object
|
|
||||||
{
|
|
||||||
const std::vector<Cimage> &ourImages = graphics->getDef(obj)->ourImages;
|
|
||||||
SDL_Surface *bitmap = ourImages[(info->anim + getPhaseShift(obj)) % ourImages.size()].bitmap;
|
|
||||||
|
|
||||||
//setting appropriate flag color
|
|
||||||
if(color < PlayerColor::PLAYER_LIMIT || color==PlayerColor::NEUTRAL)
|
|
||||||
CSDL_Ext::setPlayerColor(bitmap, color);
|
|
||||||
|
|
||||||
drawNormalObject(targetSurf, bitmap, &pp);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1109,6 +996,109 @@ void CMapHandler::CMapBlitter::blit(SDL_Surface * targetSurf, const MapDrawingIn
|
|||||||
SDL_SetClipRect(targetSurf, &prevClip);
|
SDL_SetClipRect(targetSurf, &prevClip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CMapHandler::AnimBitmapHolder CMapHandler::CMapBlitter::findHeroBitmap(const CGHeroInstance * hero, int anim) const
|
||||||
|
{
|
||||||
|
if(hero && hero->moveDir && hero->type) //it's hero or boat
|
||||||
|
{
|
||||||
|
if(hero->tempOwner >= PlayerColor::PLAYER_LIMIT) //Neutral hero?
|
||||||
|
{
|
||||||
|
logGlobal->errorStream() << "A neutral hero (" << hero->name << ") at " << hero->pos << ". Should not happen!";
|
||||||
|
return CMapHandler::AnimBitmapHolder();
|
||||||
|
}
|
||||||
|
|
||||||
|
//pick graphics of hero (or boat if hero is sailing)
|
||||||
|
CDefEssential * def = nullptr;
|
||||||
|
if (hero->boat)
|
||||||
|
def = graphics->boatAnims[hero->boat->subID];
|
||||||
|
else
|
||||||
|
def = graphics->heroAnims[hero->appearance.animationFile];
|
||||||
|
|
||||||
|
bool moving = !hero->isStanding;
|
||||||
|
int framesOffset = moving ? anim % FRAMES_PER_MOVE_ANIM_GROUP : 0;
|
||||||
|
int index = findAnimIndexByGroup(def, getHeroFrameNum(hero->moveDir, moving));
|
||||||
|
if (index >= 0)
|
||||||
|
{
|
||||||
|
auto heroBitmap = def->ourImages[index + framesOffset].bitmap;
|
||||||
|
auto flagBitmap = findFlagBitmap(hero, anim, &hero->tempOwner, index + 35);
|
||||||
|
return CMapHandler::AnimBitmapHolder(heroBitmap, flagBitmap, moving);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return CMapHandler::AnimBitmapHolder();
|
||||||
|
}
|
||||||
|
|
||||||
|
CMapHandler::AnimBitmapHolder CMapHandler::CMapBlitter::findBoatBitmap(const CGBoat * boat, int anim) const
|
||||||
|
{
|
||||||
|
auto def = graphics->boatAnims[boat->subID];
|
||||||
|
int index = findAnimIndexByGroup(def, getHeroFrameNum(boat->direction, false));
|
||||||
|
if (index < 0)
|
||||||
|
return CMapHandler::AnimBitmapHolder();
|
||||||
|
return CMapHandler::AnimBitmapHolder(def->ourImages[index].bitmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Surface * CMapHandler::CMapBlitter::findFlagBitmap(const CGHeroInstance * hero, int anim, const PlayerColor * color, int indexOffset) const
|
||||||
|
{
|
||||||
|
if (!hero)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
if (hero->boat)
|
||||||
|
return findBoatFlagBitmap(hero->boat, anim, color, indexOffset, hero->moveDir);
|
||||||
|
return findHeroFlagBitmap(hero, anim, color, indexOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Surface * CMapHandler::CMapBlitter::findHeroFlagBitmap(const CGHeroInstance * hero, int anim, const PlayerColor * color, int indexOffset) const
|
||||||
|
{
|
||||||
|
return findFlagBitmapInternal(graphics->flags4[color->getNum()], anim, indexOffset, hero->moveDir, !hero->isStanding);
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Surface * CMapHandler::CMapBlitter::findBoatFlagBitmap(const CGBoat * boat, int anim, const PlayerColor * color, int indexOffset, ui8 dir) const
|
||||||
|
{
|
||||||
|
std::vector<CDefEssential *> Graphics::*flg = nullptr;
|
||||||
|
switch (boat->subID)
|
||||||
|
{
|
||||||
|
case 0: flg = &Graphics::flags1; break;
|
||||||
|
case 1: flg = &Graphics::flags2; break;
|
||||||
|
case 2: flg = &Graphics::flags3; break;
|
||||||
|
default: logGlobal->errorStream() << "Not supported boat subtype: " << boat->subID; return nullptr;
|
||||||
|
}
|
||||||
|
return findFlagBitmapInternal((graphics->*flg)[color->getNum()], anim, indexOffset, dir, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Surface * CMapHandler::CMapBlitter::findFlagBitmapInternal(const CDefEssential * def, int anim, int indexOffset, ui8 dir, bool moving) const
|
||||||
|
{
|
||||||
|
if (moving)
|
||||||
|
return def->ourImages[indexOffset + anim % FRAMES_PER_MOVE_ANIM_GROUP].bitmap;
|
||||||
|
return def->ourImages[getHeroFrameNum(dir, false) * FRAMES_PER_MOVE_ANIM_GROUP + (anim / 4) % FRAMES_PER_MOVE_ANIM_GROUP].bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CMapHandler::CMapBlitter::findAnimIndexByGroup(const CDefEssential * def, int groupNum) const
|
||||||
|
{
|
||||||
|
auto iter = std::find_if(def->ourImages.begin(), def->ourImages.end(), [&](const Cimage &img){ return img.groupNumber == groupNum; });
|
||||||
|
if (iter == def->ourImages.end())
|
||||||
|
return -1;
|
||||||
|
return static_cast<int>(iter - def->ourImages.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
CMapHandler::AnimBitmapHolder CMapHandler::CMapBlitter::findObjectBitmap(const CGObjectInstance * obj, int anim) const
|
||||||
|
{
|
||||||
|
if (!obj)
|
||||||
|
return CMapHandler::AnimBitmapHolder();
|
||||||
|
if (obj->ID == Obj::HERO)
|
||||||
|
return findHeroBitmap(static_cast<const CGHeroInstance*>(obj), anim);
|
||||||
|
if (obj->ID == Obj::BOAT)
|
||||||
|
return findBoatBitmap(static_cast<const CGBoat*>(obj), anim);
|
||||||
|
|
||||||
|
// normal object
|
||||||
|
|
||||||
|
const std::vector<Cimage> &ourImages = graphics->getDef(obj)->ourImages;
|
||||||
|
SDL_Surface *bitmap = ourImages[(anim + getPhaseShift(obj)) % ourImages.size()].bitmap;
|
||||||
|
|
||||||
|
//setting appropriate flag color
|
||||||
|
const PlayerColor &color = obj->tempOwner;
|
||||||
|
if(color < PlayerColor::PLAYER_LIMIT || color==PlayerColor::NEUTRAL)
|
||||||
|
CSDL_Ext::setPlayerColor(bitmap, color);
|
||||||
|
return CMapHandler::AnimBitmapHolder(bitmap);
|
||||||
|
}
|
||||||
|
|
||||||
ui8 CMapHandler::CMapBlitter::getPhaseShift(const CGObjectInstance *object) const
|
ui8 CMapHandler::CMapBlitter::getPhaseShift(const CGObjectInstance *object) const
|
||||||
{
|
{
|
||||||
auto i = parent->animationPhase.find(object);
|
auto i = parent->animationPhase.find(object);
|
||||||
@ -1181,29 +1171,60 @@ bool CMapHandler::updateObjectsFade()
|
|||||||
++iter;
|
++iter;
|
||||||
else // fade finished
|
else // fade finished
|
||||||
{
|
{
|
||||||
|
auto &objs = ttiles[pos.x][pos.y][pos.z].objects;
|
||||||
if (anim->fadingMode == CFadeAnimation::EMode::OUT)
|
for (auto objIter = objs.begin(); objIter != objs.end(); ++objIter)
|
||||||
{
|
{
|
||||||
auto &objs = ttiles[pos.x][pos.y][pos.z].objects;
|
if ((*objIter).fadeAnimKey == (*iter).first)
|
||||||
for (auto objIter = objs.begin(); objIter != objs.end(); ++objIter)
|
{
|
||||||
{
|
if (anim->fadingMode == CFadeAnimation::EMode::OUT)
|
||||||
if ((*objIter).fadeAnimKey == (*iter).first)
|
objs.erase(objIter); // if this was fadeout, remove the object from the map
|
||||||
{
|
else
|
||||||
if (anim->fadingMode == CFadeAnimation::EMode::OUT)
|
(*objIter).fadeAnimKey = -1; // for fadein, just remove its connection to the finished fade
|
||||||
objs.erase(objIter); // if this was fadeout, remove the object from the map
|
break;
|
||||||
else
|
|
||||||
(*objIter).fadeAnimKey = -1; // for fadein, just remove its connection to the finished fade
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
iter = fadeAnims.erase(iter);
|
iter = fadeAnims.erase(iter);
|
||||||
|
logAnim->traceStream() << "Fade anim finished, remaining: " << fadeAnims.size();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return !fadeAnims.empty();
|
return !fadeAnims.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CMapHandler::startObjectFade(TerrainTileObject & obj, bool in, int3 pos)
|
||||||
|
{
|
||||||
|
SDL_Surface * fadeBitmap;
|
||||||
|
|
||||||
|
auto objData = normalBlitter->findObjectBitmap(obj.obj, 0);
|
||||||
|
if (objData.objBitmap)
|
||||||
|
{
|
||||||
|
if (objData.isMoving) // ignore fading of moving objects (for now?)
|
||||||
|
{
|
||||||
|
logAnim->debugStream() << "Ignoring fade of moving object";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fadeBitmap = CSDL_Ext::newSurface(32, 32); // TODO cache these bitmaps instead of creating new ones?
|
||||||
|
Rect objSrcRect(obj.rect.x, obj.rect.y, 32, 32);
|
||||||
|
CSDL_Ext::blit8bppAlphaTo24bpp(objData.objBitmap, &objSrcRect, fadeBitmap, nullptr);
|
||||||
|
if (objData.flagBitmap)
|
||||||
|
{
|
||||||
|
if (obj.obj->pos.x - 1 == pos.x && obj.obj->pos.y - 1 == pos.y) // -1 to draw flag in top-center instead of right-bottom; kind of a hack
|
||||||
|
{
|
||||||
|
Rect flagSrcRect(32, 0, 32, 32);
|
||||||
|
CSDL_Ext::blitSurface(objData.flagBitmap, &flagSrcRect, fadeBitmap, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto anim = new CFadeAnimation();
|
||||||
|
anim->init(in ? CFadeAnimation::EMode::IN : CFadeAnimation::EMode::OUT, fadeBitmap, true);
|
||||||
|
fadeAnims[++fadeAnimCounter] = std::pair<int3, CFadeAnimation*>(pos, anim);
|
||||||
|
obj.fadeAnimKey = fadeAnimCounter;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool CMapHandler::printObject(const CGObjectInstance *obj, bool fadein /* = false */)
|
bool CMapHandler::printObject(const CGObjectInstance *obj, bool fadein /* = false */)
|
||||||
{
|
{
|
||||||
if (!graphics->getDef(obj))
|
if (!graphics->getDef(obj))
|
||||||
@ -1223,20 +1244,17 @@ bool CMapHandler::printObject(const CGObjectInstance *obj, bool fadein /* = fals
|
|||||||
cr.x = fx*32;
|
cr.x = fx*32;
|
||||||
cr.y = fy*32;
|
cr.y = fy*32;
|
||||||
TerrainTileObject toAdd(obj, cr);
|
TerrainTileObject toAdd(obj, cr);
|
||||||
if (fadein && ADVOPT.objectFading)
|
|
||||||
{
|
|
||||||
auto tmp = CSDL_Ext::newSurface(bitmap->w, bitmap->h);
|
|
||||||
SDL_BlitSurface(bitmap, nullptr, tmp, nullptr); // can't be 8bpp for fading
|
|
||||||
auto anim = new CFadeAnimation();
|
|
||||||
anim->init(CFadeAnimation::EMode::IN, tmp, true);
|
|
||||||
fadeAnims[++fadeAnimCounter] = std::pair<int3, CFadeAnimation*>(int3(fx, fy, obj->pos.z), anim);
|
|
||||||
toAdd.fadeAnimKey = fadeAnimCounter;
|
|
||||||
}
|
|
||||||
|
|
||||||
if((obj->pos.x + fx - tilesW+1)>=0 && (obj->pos.x + fx - tilesW+1)<ttiles.size()-frameW && (obj->pos.y + fy - tilesH+1)>=0 && (obj->pos.y + fy - tilesH+1)<ttiles[0].size()-frameH)
|
if((obj->pos.x + fx - tilesW+1)>=0 && (obj->pos.x + fx - tilesW+1)<ttiles.size()-frameW && (obj->pos.y + fy - tilesH+1)>=0 && (obj->pos.y + fy - tilesH+1)<ttiles[0].size()-frameH)
|
||||||
{
|
{
|
||||||
TerrainTile2 & curt = ttiles[obj->pos.x + fx - tilesW+1][obj->pos.y + fy - tilesH+1][obj->pos.z];
|
int3 pos(obj->pos.x + fx - tilesW + 1, obj->pos.y + fy - tilesH + 1, obj->pos.z);
|
||||||
|
TerrainTile2 & curt = ttiles[pos.x][pos.y][pos.z];
|
||||||
|
|
||||||
|
if (fadein && ADVOPT.objectFading)
|
||||||
|
{
|
||||||
|
startObjectFade(toAdd, true, pos);
|
||||||
|
}
|
||||||
|
|
||||||
auto i = curt.objects.begin();
|
auto i = curt.objects.begin();
|
||||||
for(; i != curt.objects.end(); i++)
|
for(; i != curt.objects.end(); i++)
|
||||||
{
|
{
|
||||||
@ -1259,6 +1277,7 @@ bool CMapHandler::printObject(const CGObjectInstance *obj, bool fadein /* = fals
|
|||||||
|
|
||||||
bool CMapHandler::hideObject(const CGObjectInstance *obj, bool fadeout /* = false */)
|
bool CMapHandler::hideObject(const CGObjectInstance *obj, bool fadeout /* = false */)
|
||||||
{
|
{
|
||||||
|
// do we actually need to search through the whole map for this?
|
||||||
for (size_t i=0; i<map->width; i++)
|
for (size_t i=0; i<map->width; i++)
|
||||||
{
|
{
|
||||||
for (size_t j=0; j<map->height; j++)
|
for (size_t j=0; j<map->height; j++)
|
||||||
@ -1269,16 +1288,10 @@ bool CMapHandler::hideObject(const CGObjectInstance *obj, bool fadeout /* = fals
|
|||||||
{
|
{
|
||||||
if (ttiles[i][j][k].objects[x].obj->id == obj->id)
|
if (ttiles[i][j][k].objects[x].obj->id == obj->id)
|
||||||
{
|
{
|
||||||
if (fadeout && ADVOPT.objectFading) // erase delayed until end of fadeout
|
if (fadeout && ADVOPT.objectFading) // object should be faded == erase is delayed until the end of fadeout
|
||||||
{
|
{
|
||||||
auto bitmap = graphics->getDef(obj)->ourImages[0].bitmap;
|
if (!startObjectFade(ttiles[i][j][k].objects[x], false, int3(i, j, k)))
|
||||||
auto tmp = CSDL_Ext::newSurface(bitmap->w, bitmap->h); // TODO cache these bitmaps instead of creating new ones?
|
ttiles[i][j][k].objects.erase(ttiles[i][j][k].objects.begin() + x);
|
||||||
SDL_BlitSurface(bitmap, nullptr, tmp, nullptr); // can't be 8bpp for fading
|
|
||||||
|
|
||||||
auto anim = new CFadeAnimation();
|
|
||||||
anim->init(CFadeAnimation::EMode::OUT, tmp, true);
|
|
||||||
fadeAnims[++fadeAnimCounter] = std::pair<int3, CFadeAnimation*>(int3(i, j, k), anim);
|
|
||||||
ttiles[i][j][k].objects[x].fadeAnimKey = fadeAnimCounter;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ttiles[i][j][k].objects.erase(ttiles[i][j][k].objects.begin() + x);
|
ttiles[i][j][k].objects.erase(ttiles[i][j][k].objects.begin() + x);
|
||||||
@ -1367,6 +1380,11 @@ ui8 CMapHandler::getDir(const int3 &a, const int3 &b)
|
|||||||
return -2; //shouldn't happen
|
return -2; //shouldn't happen
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CMapHandler::canStartHeroMovement()
|
||||||
|
{
|
||||||
|
return fadeAnims.empty(); // don't allow movement during fade animation
|
||||||
|
}
|
||||||
|
|
||||||
void shiftColors(SDL_Surface *img, int from, int howMany) //shifts colors in palette
|
void shiftColors(SDL_Surface *img, int from, int howMany) //shifts colors in palette
|
||||||
{
|
{
|
||||||
//works with at most 16 colors, if needed more -> increase values
|
//works with at most 16 colors, if needed more -> increase values
|
||||||
|
@ -17,15 +17,16 @@
|
|||||||
|
|
||||||
class CGObjectInstance;
|
class CGObjectInstance;
|
||||||
class CGHeroInstance;
|
class CGHeroInstance;
|
||||||
|
class CGBoat;
|
||||||
class CMap;
|
class CMap;
|
||||||
class CGDefInfo;
|
class CGDefInfo;
|
||||||
class CGObjectInstance;
|
|
||||||
class CDefHandler;
|
class CDefHandler;
|
||||||
struct TerrainTile;
|
struct TerrainTile;
|
||||||
struct SDL_Surface;
|
struct SDL_Surface;
|
||||||
struct SDL_Rect;
|
struct SDL_Rect;
|
||||||
class CDefEssential;
|
class CDefEssential;
|
||||||
class CFadeAnimation;
|
class CFadeAnimation;
|
||||||
|
class PlayerColor;
|
||||||
|
|
||||||
enum class EWorldViewIcon
|
enum class EWorldViewIcon
|
||||||
{
|
{
|
||||||
@ -180,11 +181,26 @@ class CMapHandler
|
|||||||
SDL_Surface * cacheWorldViewEntry(EMapCacheType type, intptr_t key, SDL_Surface * entry);
|
SDL_Surface * cacheWorldViewEntry(EMapCacheType type, intptr_t key, SDL_Surface * entry);
|
||||||
intptr_t genKey(intptr_t realPtr, ui8 mod);
|
intptr_t genKey(intptr_t realPtr, ui8 mod);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// helper struct to pass around resolved bitmaps of an object; surfaces can be nullptr if object doesn't have bitmap of that type
|
||||||
|
struct AnimBitmapHolder
|
||||||
|
{
|
||||||
|
SDL_Surface * objBitmap; // main object bitmap
|
||||||
|
SDL_Surface * flagBitmap; // flag bitmap for the object (probably only for heroes and boats with heroes)
|
||||||
|
bool isMoving; // indicates if the object is moving (again, heroes/boats only)
|
||||||
|
|
||||||
|
AnimBitmapHolder(SDL_Surface * objBitmap_ = nullptr, SDL_Surface * flagBitmap_ = nullptr, bool moving = false)
|
||||||
|
: objBitmap(objBitmap_),
|
||||||
|
flagBitmap(flagBitmap_),
|
||||||
|
isMoving(moving)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class CMapBlitter
|
class CMapBlitter
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
|
static constexpr int FRAMES_PER_MOVE_ANIM_GROUP = 8;
|
||||||
CMapHandler * parent; // ptr to enclosing map handler; generally for legacy reasons, probably could/should be refactored out of here
|
CMapHandler * parent; // ptr to enclosing map handler; generally for legacy reasons, probably could/should be refactored out of here
|
||||||
int tileSize; // size of a tile drawn on map [in pixels]
|
int tileSize; // size of a tile drawn on map [in pixels]
|
||||||
int halfTileSizeCeil; // half of the tile size, rounded up
|
int halfTileSizeCeil; // half of the tile size, rounded up
|
||||||
@ -211,10 +227,8 @@ class CMapHandler
|
|||||||
virtual void drawRoad(SDL_Surface * targetSurf, const TerrainTile & tinfo, const TerrainTile * tinfoUpper) const;
|
virtual void drawRoad(SDL_Surface * targetSurf, const TerrainTile & tinfo, const TerrainTile * tinfoUpper) const;
|
||||||
/// draws all objects on current tile (higher-level logic, unlike other draw*** methods)
|
/// draws all objects on current tile (higher-level logic, unlike other draw*** methods)
|
||||||
virtual void drawObjects(SDL_Surface * targetSurf, const TerrainTile2 & tile) const;
|
virtual void drawObjects(SDL_Surface * targetSurf, const TerrainTile2 & tile) const;
|
||||||
/// current tile: draws non-hero object with given image/position
|
virtual void drawObject(SDL_Surface * targetSurf, SDL_Surface * sourceSurf, SDL_Rect * sourceRect, bool moving) const;
|
||||||
virtual void drawNormalObject(SDL_Surface * targetSurf, SDL_Surface * sourceSurf, SDL_Rect * sourceRect) const;
|
|
||||||
virtual void drawHeroFlag(SDL_Surface * targetSurf, SDL_Surface * sourceSurf, SDL_Rect * sourceRect, SDL_Rect * destRect, bool moving) const;
|
virtual void drawHeroFlag(SDL_Surface * targetSurf, SDL_Surface * sourceSurf, SDL_Rect * sourceRect, SDL_Rect * destRect, bool moving) const;
|
||||||
virtual void drawHero(SDL_Surface * targetSurf, SDL_Surface * sourceSurf, SDL_Rect * sourceRect, bool moving) const;
|
|
||||||
|
|
||||||
// second drawing pass
|
// second drawing pass
|
||||||
|
|
||||||
@ -245,10 +259,21 @@ class CMapHandler
|
|||||||
virtual bool canDrawObject(const CGObjectInstance * obj) const;
|
virtual bool canDrawObject(const CGObjectInstance * obj) const;
|
||||||
virtual bool canDrawCurrentTile() const;
|
virtual bool canDrawCurrentTile() const;
|
||||||
|
|
||||||
|
// internal helper methods to choose correct bitmap(s) for object; called internally by findObjectBitmap
|
||||||
|
AnimBitmapHolder findHeroBitmap(const CGHeroInstance * hero, int anim) const;
|
||||||
|
AnimBitmapHolder findBoatBitmap(const CGBoat * hero, int anim) const;
|
||||||
|
SDL_Surface * findFlagBitmap(const CGHeroInstance * obj, int anim, const PlayerColor * color, int indexOffset) const;
|
||||||
|
SDL_Surface * findHeroFlagBitmap(const CGHeroInstance * obj, int anim, const PlayerColor * color, int indexOffset) const;
|
||||||
|
SDL_Surface * findBoatFlagBitmap(const CGBoat * obj, int anim, const PlayerColor * color, int indexOffset, ui8 dir) const;
|
||||||
|
SDL_Surface * findFlagBitmapInternal(const CDefEssential * def, int anim, int indexOffset, ui8 dir, bool moving) const;
|
||||||
|
int findAnimIndexByGroup(const CDefEssential * def, int groupNum) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CMapBlitter(CMapHandler * p) : parent(p) {}
|
CMapBlitter(CMapHandler * p) : parent(p) {}
|
||||||
virtual ~CMapBlitter(){}
|
virtual ~CMapBlitter(){}
|
||||||
void blit(SDL_Surface * targetSurf, const MapDrawingInfo * info);
|
void blit(SDL_Surface * targetSurf, const MapDrawingInfo * info);
|
||||||
|
/// helper method that chooses correct bitmap(s) for given object
|
||||||
|
AnimBitmapHolder findObjectBitmap(const CGObjectInstance * obj, int anim) const;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -273,14 +298,13 @@ class CMapHandler
|
|||||||
SDL_Surface * targetSurf, SDL_Rect * destRect, bool alphaBlit = false, ui8 rotationInfo = 0u) const override;
|
SDL_Surface * targetSurf, SDL_Rect * destRect, bool alphaBlit = false, ui8 rotationInfo = 0u) const override;
|
||||||
|
|
||||||
void drawTileOverlay(SDL_Surface * targetSurf, const TerrainTile2 & tile) const override;
|
void drawTileOverlay(SDL_Surface * targetSurf, const TerrainTile2 & tile) const override;
|
||||||
void drawNormalObject(SDL_Surface * targetSurf, SDL_Surface * sourceSurf, SDL_Rect * sourceRect) const override;
|
|
||||||
void drawHeroFlag(SDL_Surface * targetSurf, SDL_Surface * sourceSurf, SDL_Rect * sourceRect, SDL_Rect * destRect, bool moving) const override;
|
void drawHeroFlag(SDL_Surface * targetSurf, SDL_Surface * sourceSurf, SDL_Rect * sourceRect, SDL_Rect * destRect, bool moving) const override;
|
||||||
void drawHero(SDL_Surface * targetSurf, SDL_Surface * sourceSurf, SDL_Rect * sourceRect, bool moving) const;
|
void drawObject(SDL_Surface * targetSurf, SDL_Surface * sourceSurf, SDL_Rect * sourceRect, bool moving) const override;
|
||||||
void drawFrame(SDL_Surface * targetSurf) const override {}
|
void drawFrame(SDL_Surface * targetSurf) const override {}
|
||||||
void init(const MapDrawingInfo * info) override;
|
void init(const MapDrawingInfo * info) override;
|
||||||
SDL_Rect clip(SDL_Surface * targetSurf) const override;
|
SDL_Rect clip(SDL_Surface * targetSurf) const override;
|
||||||
|
|
||||||
ui8 getHeroFrameNum(ui8 dir, bool isMoving) const override { return 0u; }
|
// ui8 getHeroFrameNum(ui8 dir, bool isMoving) const override { return 0u; }
|
||||||
ui8 getPhaseShift(const CGObjectInstance *object) const override { return 0u; }
|
ui8 getPhaseShift(const CGObjectInstance *object) const override { return 0u; }
|
||||||
|
|
||||||
void drawScaledRotatedElement(EMapCacheType type, SDL_Surface * baseSurf, SDL_Surface * targetSurf, ui8 rotation,
|
void drawScaledRotatedElement(EMapCacheType type, SDL_Surface * baseSurf, SDL_Surface * targetSurf, ui8 rotation,
|
||||||
@ -314,6 +338,7 @@ class CMapHandler
|
|||||||
|
|
||||||
CMapBlitter * resolveBlitter(const MapDrawingInfo * info) const;
|
CMapBlitter * resolveBlitter(const MapDrawingInfo * info) const;
|
||||||
bool updateObjectsFade();
|
bool updateObjectsFade();
|
||||||
|
bool startObjectFade(TerrainTileObject & obj, bool in, int3 pos);
|
||||||
public:
|
public:
|
||||||
PseudoV< PseudoV< PseudoV<TerrainTile2> > > ttiles; //informations about map tiles
|
PseudoV< PseudoV< PseudoV<TerrainTile2> > > ttiles; //informations about map tiles
|
||||||
int3 sizes; //map size (x = width, y = height, z = number of levels)
|
int3 sizes; //map size (x = width, y = height, z = number of levels)
|
||||||
@ -363,6 +388,8 @@ public:
|
|||||||
void updateWater();
|
void updateWater();
|
||||||
void validateRectTerr(SDL_Rect * val, const SDL_Rect * ext); //terrainRect helper
|
void validateRectTerr(SDL_Rect * val, const SDL_Rect * ext); //terrainRect helper
|
||||||
static ui8 getDir(const int3 & a, const int3 & b); //returns direction number in range 0 - 7 (0 is left top, clockwise) [direction: form a to b]
|
static ui8 getDir(const int3 & a, const int3 & b); //returns direction number in range 0 - 7 (0 is left top, clockwise) [direction: form a to b]
|
||||||
|
/// determines if the map is ready to handle new hero movement (not available during fading animations)
|
||||||
|
bool canStartHeroMovement();
|
||||||
|
|
||||||
void discardWorldViewCache();
|
void discardWorldViewCache();
|
||||||
|
|
||||||
|
@ -693,7 +693,7 @@ void CAdvMapInt::fsleepWake()
|
|||||||
void CAdvMapInt::fmoveHero()
|
void CAdvMapInt::fmoveHero()
|
||||||
{
|
{
|
||||||
const CGHeroInstance *h = curHero();
|
const CGHeroInstance *h = curHero();
|
||||||
if (!h || !terrain.currentPath)
|
if (!h || !terrain.currentPath || !CGI->mh->canStartHeroMovement())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
LOCPLINT->moveHero(h, *terrain.currentPath);
|
LOCPLINT->moveHero(h, *terrain.currentPath);
|
||||||
@ -1169,6 +1169,9 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key)
|
|||||||
#endif // VCMI_SDL1
|
#endif // VCMI_SDL1
|
||||||
if(k < 0 || k > 8)
|
if(k < 0 || k > 8)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!CGI->mh->canStartHeroMovement())
|
||||||
|
return;
|
||||||
|
|
||||||
int3 dir = directions[k];
|
int3 dir = directions[k];
|
||||||
|
|
||||||
@ -1439,7 +1442,8 @@ void CAdvMapInt::tileLClicked(const int3 &mapPos)
|
|||||||
{
|
{
|
||||||
if (terrain.currentPath && terrain.currentPath->endPos() == mapPos)//we'll be moving
|
if (terrain.currentPath && terrain.currentPath->endPos() == mapPos)//we'll be moving
|
||||||
{
|
{
|
||||||
LOCPLINT->moveHero(currentHero,*terrain.currentPath);
|
if (CGI->mh->canStartHeroMovement())
|
||||||
|
LOCPLINT->moveHero(currentHero,*terrain.currentPath);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else/* if(mp.z == currentHero->pos.z)*/ //remove old path and find a new one if we clicked on the map level on which hero is present
|
else/* if(mp.z == currentHero->pos.z)*/ //remove old path and find a new one if we clicked on the map level on which hero is present
|
||||||
|
Loading…
x
Reference in New Issue
Block a user