mirror of
https://github.com/vcmi/vcmi.git
synced 2025-01-12 02:28:11 +02:00
Merge pull request #1146 from IvanSavenko/ray_projectile
Implemented ray-like projectiles for shooters
This commit is contained in:
commit
3133c238b8
@ -588,6 +588,11 @@ bool MusicEntry::play()
|
||||
float timeToStart = owner->trackPositions[currentName];
|
||||
startPosition = std::round(timeToStart * 1000);
|
||||
|
||||
// erase stored position:
|
||||
// if music track will be interrupted again - new position will be written in stop() method
|
||||
// if music track is not interrupted and will finish by timeout/end of file - it will restart from begginning as it should
|
||||
owner->trackPositions.erase( owner->trackPositions.find(currentName) );
|
||||
|
||||
if (Mix_FadeInMusicPos(music, 1, 1000, timeToStart) == -1)
|
||||
{
|
||||
logGlobal->error("Unable to play music (%s)", Mix_GetError());
|
||||
|
@ -218,27 +218,6 @@ void CPlayerInterface::yourTurn()
|
||||
acceptTurn();
|
||||
}
|
||||
|
||||
STRONG_INLINE void subRect(const int & x, const int & y, const int & z, const SDL_Rect & r, const ObjectInstanceID & hid)
|
||||
{
|
||||
TerrainTile2 & hlp = CGI->mh->ttiles[z][x][y];
|
||||
for (auto & elem : hlp.objects)
|
||||
if (elem.obj && elem.obj->id == hid)
|
||||
{
|
||||
elem.rect = r;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
STRONG_INLINE void delObjRect(const int & x, const int & y, const int & z, const ObjectInstanceID & hid)
|
||||
{
|
||||
TerrainTile2 & hlp = CGI->mh->ttiles[z][x][y];
|
||||
for (int h=0; h<hlp.objects.size(); ++h)
|
||||
if (hlp.objects[h].obj && hlp.objects[h].obj->id == hid)
|
||||
{
|
||||
hlp.objects.erase(hlp.objects.begin()+h);
|
||||
return;
|
||||
}
|
||||
}
|
||||
void CPlayerInterface::heroMoved(const TryMoveHero & details, bool verbose)
|
||||
{
|
||||
EVENT_HANDLER_CALLED_BY_CLIENT;
|
||||
@ -1744,432 +1723,144 @@ void CPlayerInterface::initMovement( const TryMoveHero &details, const CGHeroIns
|
||||
{
|
||||
auto subArr = (CGI->mh->ttiles)[hp.z];
|
||||
|
||||
if (details.end.x+1 == details.start.x && details.end.y+1 == details.start.y) //tl
|
||||
ho->isStanding = false;
|
||||
|
||||
int heroWidth = ho->appearance->getWidth();
|
||||
int heroHeight = ho->appearance->getHeight();
|
||||
|
||||
int tileMinX = std::min(details.start.x, details.end.x) - heroWidth;
|
||||
int tileMaxX = std::max(details.start.x, details.end.x);
|
||||
int tileMinY = std::min(details.start.y, details.end.y) - heroHeight;
|
||||
int tileMaxY = std::max(details.start.y, details.end.y);
|
||||
|
||||
// determine tiles on which hero will be visible during movement and add hero as visible object on these tiles where necessary
|
||||
for ( int tileX = tileMinX; tileX <= tileMaxX; ++tileX)
|
||||
{
|
||||
//ho->moveDir = 1;
|
||||
ho->isStanding = false;
|
||||
subArr[hp.x-3][hp.y-2].objects.push_back(TerrainTileObject(ho, genRect(32, 32, -31, -31)));
|
||||
subArr[hp.x-2][hp.y-2].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 1, -31)));
|
||||
subArr[hp.x-1][hp.y-2].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 33, -31)));
|
||||
subArr[hp.x][hp.y-2].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 65, -31)));
|
||||
for ( int tileY = tileMinY; tileY <= tileMaxY; ++tileY)
|
||||
{
|
||||
bool heroVisibleHere = false;
|
||||
auto & tile = subArr[tileX][tileY];
|
||||
|
||||
subArr[hp.x-3][hp.y-1].objects.push_back(TerrainTileObject(ho, genRect(32, 32, -31, 1)));
|
||||
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, 1, 1), ho->id);
|
||||
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 33, 1), ho->id);
|
||||
subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 65, 1), ho->id);
|
||||
for ( auto const & obj : tile.objects)
|
||||
{
|
||||
if (obj.obj == ho)
|
||||
{
|
||||
heroVisibleHere = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
subArr[hp.x-3][hp.y].objects.push_back(TerrainTileObject(ho, genRect(32, 32, -31, 33)));
|
||||
subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, 1, 33), ho->id);
|
||||
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 33, 33), ho->id);
|
||||
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 65, 33), ho->id);
|
||||
|
||||
std::stable_sort(subArr[hp.x-3][hp.y-2].objects.begin(), subArr[hp.x-3][hp.y-2].objects.end(), objectBlitOrderSorter);
|
||||
std::stable_sort(subArr[hp.x-2][hp.y-2].objects.begin(), subArr[hp.x-2][hp.y-2].objects.end(), objectBlitOrderSorter);
|
||||
std::stable_sort(subArr[hp.x-1][hp.y-2].objects.begin(), subArr[hp.x-1][hp.y-2].objects.end(), objectBlitOrderSorter);
|
||||
std::stable_sort(subArr[hp.x][hp.y-2].objects.begin(), subArr[hp.x][hp.y-2].objects.end(), objectBlitOrderSorter);
|
||||
|
||||
std::stable_sort(subArr[hp.x-3][hp.y-1].objects.begin(), subArr[hp.x-3][hp.y-1].objects.end(), objectBlitOrderSorter);
|
||||
|
||||
std::stable_sort(subArr[hp.x-3][hp.y].objects.begin(), subArr[hp.x-3][hp.y].objects.end(), objectBlitOrderSorter);
|
||||
}
|
||||
else if (details.end.x == details.start.x && details.end.y+1 == details.start.y) //t
|
||||
{
|
||||
//ho->moveDir = 2;
|
||||
ho->isStanding = false;
|
||||
subArr[hp.x-2][hp.y-2].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 0, -31)));
|
||||
subArr[hp.x-1][hp.y-2].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 32, -31)));
|
||||
subArr[hp.x][hp.y-2].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 64, -31)));
|
||||
|
||||
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, 0, 1), ho->id);
|
||||
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 32, 1), ho->id);
|
||||
subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 64, 1), ho->id);
|
||||
|
||||
subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, 0, 33), ho->id);
|
||||
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 32, 33), ho->id);
|
||||
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 64, 33), ho->id);
|
||||
|
||||
std::stable_sort(subArr[hp.x-2][hp.y-2].objects.begin(), subArr[hp.x-2][hp.y-2].objects.end(), objectBlitOrderSorter);
|
||||
std::stable_sort(subArr[hp.x-1][hp.y-2].objects.begin(), subArr[hp.x-1][hp.y-2].objects.end(), objectBlitOrderSorter);
|
||||
std::stable_sort(subArr[hp.x][hp.y-2].objects.begin(), subArr[hp.x][hp.y-2].objects.end(), objectBlitOrderSorter);
|
||||
}
|
||||
else if (details.end.x-1 == details.start.x && details.end.y+1 == details.start.y) //tr
|
||||
{
|
||||
//ho->moveDir = 3;
|
||||
ho->isStanding = false;
|
||||
subArr[hp.x-2][hp.y-2].objects.push_back(TerrainTileObject(ho, genRect(32, 32, -1, -31)));
|
||||
subArr[hp.x-1][hp.y-2].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 31, -31)));
|
||||
subArr[hp.x][hp.y-2].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 63, -31)));
|
||||
subArr[hp.x+1][hp.y-2].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 95, -31)));
|
||||
|
||||
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, -1, 1), ho->id);
|
||||
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 31, 1), ho->id);
|
||||
subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 63, 1), ho->id);
|
||||
subArr[hp.x+1][hp.y-1].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 95, 1)));
|
||||
|
||||
subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, -1, 33), ho->id);
|
||||
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 31, 33), ho->id);
|
||||
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 63, 33), ho->id);
|
||||
subArr[hp.x+1][hp.y].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 95, 33)));
|
||||
|
||||
std::stable_sort(subArr[hp.x-2][hp.y-2].objects.begin(), subArr[hp.x-2][hp.y-2].objects.end(), objectBlitOrderSorter);
|
||||
std::stable_sort(subArr[hp.x-1][hp.y-2].objects.begin(), subArr[hp.x-1][hp.y-2].objects.end(), objectBlitOrderSorter);
|
||||
std::stable_sort(subArr[hp.x][hp.y-2].objects.begin(), subArr[hp.x][hp.y-2].objects.end(), objectBlitOrderSorter);
|
||||
std::stable_sort(subArr[hp.x+1][hp.y-2].objects.begin(), subArr[hp.x+1][hp.y-2].objects.end(), objectBlitOrderSorter);
|
||||
|
||||
std::stable_sort(subArr[hp.x+1][hp.y-1].objects.begin(), subArr[hp.x+1][hp.y-1].objects.end(), objectBlitOrderSorter);
|
||||
|
||||
std::stable_sort(subArr[hp.x+1][hp.y].objects.begin(), subArr[hp.x+1][hp.y].objects.end(), objectBlitOrderSorter);
|
||||
}
|
||||
else if (details.end.x-1 == details.start.x && details.end.y == details.start.y) //r
|
||||
{
|
||||
//ho->moveDir = 4;
|
||||
ho->isStanding = false;
|
||||
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, -1, 0), ho->id);
|
||||
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 31, 0), ho->id);
|
||||
subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 63, 0), ho->id);
|
||||
subArr[hp.x+1][hp.y-1].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 95, 0)));
|
||||
|
||||
subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, -1, 32), ho->id);
|
||||
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 31, 32), ho->id);
|
||||
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 63, 32), ho->id);
|
||||
subArr[hp.x+1][hp.y].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 95, 32)));
|
||||
|
||||
std::stable_sort(subArr[hp.x+1][hp.y-1].objects.begin(), subArr[hp.x+1][hp.y-1].objects.end(), objectBlitOrderSorter);
|
||||
|
||||
std::stable_sort(subArr[hp.x+1][hp.y].objects.begin(), subArr[hp.x+1][hp.y].objects.end(), objectBlitOrderSorter);
|
||||
}
|
||||
else if (details.end.x-1 == details.start.x && details.end.y-1 == details.start.y) //br
|
||||
{
|
||||
//ho->moveDir = 5;
|
||||
ho->isStanding = false;
|
||||
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, -1, -1), ho->id);
|
||||
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 31, -1), ho->id);
|
||||
subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 63, -1), ho->id);
|
||||
subArr[hp.x+1][hp.y-1].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 95, -1)));
|
||||
|
||||
subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, -1, 31), ho->id);
|
||||
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 31, 31), ho->id);
|
||||
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 63, 31), ho->id);
|
||||
subArr[hp.x+1][hp.y].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 95, 31)));
|
||||
|
||||
subArr[hp.x-2][hp.y+1].objects.push_back(TerrainTileObject(ho, genRect(32, 32, -1, 63)));
|
||||
subArr[hp.x-1][hp.y+1].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 31, 63)));
|
||||
subArr[hp.x][hp.y+1].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 63, 63)));
|
||||
subArr[hp.x+1][hp.y+1].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 95, 63)));
|
||||
|
||||
std::stable_sort(subArr[hp.x+1][hp.y-1].objects.begin(), subArr[hp.x+1][hp.y-1].objects.end(), objectBlitOrderSorter);
|
||||
|
||||
std::stable_sort(subArr[hp.x+1][hp.y].objects.begin(), subArr[hp.x+1][hp.y].objects.end(), objectBlitOrderSorter);
|
||||
|
||||
std::stable_sort(subArr[hp.x-2][hp.y+1].objects.begin(), subArr[hp.x-2][hp.y+1].objects.end(), objectBlitOrderSorter);
|
||||
std::stable_sort(subArr[hp.x-1][hp.y+1].objects.begin(), subArr[hp.x-1][hp.y+1].objects.end(), objectBlitOrderSorter);
|
||||
std::stable_sort(subArr[hp.x][hp.y+1].objects.begin(), subArr[hp.x][hp.y+1].objects.end(), objectBlitOrderSorter);
|
||||
std::stable_sort(subArr[hp.x+1][hp.y+1].objects.begin(), subArr[hp.x+1][hp.y+1].objects.end(), objectBlitOrderSorter);
|
||||
}
|
||||
else if (details.end.x == details.start.x && details.end.y-1 == details.start.y) //b
|
||||
{
|
||||
//ho->moveDir = 6;
|
||||
ho->isStanding = false;
|
||||
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, 0, -1), ho->id);
|
||||
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 32, -1), ho->id);
|
||||
subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 64, -1), ho->id);
|
||||
|
||||
subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, 0, 31), ho->id);
|
||||
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 32, 31), ho->id);
|
||||
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 64, 31), ho->id);
|
||||
|
||||
subArr[hp.x-2][hp.y+1].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 0, 63)));
|
||||
subArr[hp.x-1][hp.y+1].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 32, 63)));
|
||||
subArr[hp.x][hp.y+1].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 64, 63)));
|
||||
|
||||
std::stable_sort(subArr[hp.x-2][hp.y+1].objects.begin(), subArr[hp.x-2][hp.y+1].objects.end(), objectBlitOrderSorter);
|
||||
std::stable_sort(subArr[hp.x-1][hp.y+1].objects.begin(), subArr[hp.x-1][hp.y+1].objects.end(), objectBlitOrderSorter);
|
||||
std::stable_sort(subArr[hp.x][hp.y+1].objects.begin(), subArr[hp.x][hp.y+1].objects.end(), objectBlitOrderSorter);
|
||||
}
|
||||
else if (details.end.x+1 == details.start.x && details.end.y-1 == details.start.y) //bl
|
||||
{
|
||||
//ho->moveDir = 7;
|
||||
ho->isStanding = false;
|
||||
subArr[hp.x-3][hp.y-1].objects.push_back(TerrainTileObject(ho, genRect(32, 32, -31, -1)));
|
||||
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, 1, -1), ho->id);
|
||||
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 33, -1), ho->id);
|
||||
subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 65, -1), ho->id);
|
||||
|
||||
subArr[hp.x-3][hp.y].objects.push_back(TerrainTileObject(ho, genRect(32, 32, -31, 31)));
|
||||
subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, 1, 31), ho->id);
|
||||
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 33, 31), ho->id);
|
||||
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 65, 31), ho->id);
|
||||
|
||||
subArr[hp.x-3][hp.y+1].objects.push_back(TerrainTileObject(ho, genRect(32, 32, -31, 63)));
|
||||
subArr[hp.x-2][hp.y+1].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 1, 63)));
|
||||
subArr[hp.x-1][hp.y+1].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 33, 63)));
|
||||
subArr[hp.x][hp.y+1].objects.push_back(TerrainTileObject(ho, genRect(32, 32, 65, 63)));
|
||||
|
||||
std::stable_sort(subArr[hp.x-3][hp.y-1].objects.begin(), subArr[hp.x-3][hp.y-1].objects.end(), objectBlitOrderSorter);
|
||||
|
||||
std::stable_sort(subArr[hp.x-3][hp.y].objects.begin(), subArr[hp.x-3][hp.y].objects.end(), objectBlitOrderSorter);
|
||||
|
||||
std::stable_sort(subArr[hp.x-3][hp.y+1].objects.begin(), subArr[hp.x-3][hp.y+1].objects.end(), objectBlitOrderSorter);
|
||||
std::stable_sort(subArr[hp.x-2][hp.y+1].objects.begin(), subArr[hp.x-2][hp.y+1].objects.end(), objectBlitOrderSorter);
|
||||
std::stable_sort(subArr[hp.x-1][hp.y+1].objects.begin(), subArr[hp.x-1][hp.y+1].objects.end(), objectBlitOrderSorter);
|
||||
std::stable_sort(subArr[hp.x][hp.y+1].objects.begin(), subArr[hp.x][hp.y+1].objects.end(), objectBlitOrderSorter);
|
||||
}
|
||||
else if (details.end.x+1 == details.start.x && details.end.y == details.start.y) //l
|
||||
{
|
||||
//ho->moveDir = 8;
|
||||
ho->isStanding = false;
|
||||
subArr[hp.x-3][hp.y-1].objects.push_back(TerrainTileObject(ho, genRect(32, 32, -31, 0)));
|
||||
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, 1, 0), ho->id);
|
||||
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 33, 0), ho->id);
|
||||
subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 65, 0), ho->id);
|
||||
|
||||
subArr[hp.x-3][hp.y].objects.push_back(TerrainTileObject(ho, genRect(32, 32, -31, 32)));
|
||||
subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, 1, 32), ho->id);
|
||||
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 33, 32), ho->id);
|
||||
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 65, 32), ho->id);
|
||||
|
||||
std::stable_sort(subArr[hp.x-3][hp.y-1].objects.begin(), subArr[hp.x-3][hp.y-1].objects.end(), objectBlitOrderSorter);
|
||||
|
||||
std::stable_sort(subArr[hp.x-3][hp.y].objects.begin(), subArr[hp.x-3][hp.y].objects.end(), objectBlitOrderSorter);
|
||||
if ( !heroVisibleHere)
|
||||
{
|
||||
tile.objects.push_back(TerrainTileObject(ho, {0,0,32,32}));
|
||||
std::stable_sort(tile.objects.begin(), tile.objects.end(), objectBlitOrderSorter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CPlayerInterface::movementPxStep( const TryMoveHero &details, int i, const int3 &hp, const CGHeroInstance * ho )
|
||||
{
|
||||
if (details.end.x+1 == details.start.x && details.end.y+1 == details.start.y) //tl
|
||||
auto subArr = (CGI->mh->ttiles)[hp.z];
|
||||
|
||||
int heroWidth = ho->appearance->getWidth();
|
||||
int heroHeight = ho->appearance->getHeight();
|
||||
|
||||
int tileMinX = std::min(details.start.x, details.end.x) - heroWidth;
|
||||
int tileMaxX = std::max(details.start.x, details.end.x);
|
||||
int tileMinY = std::min(details.start.y, details.end.y) - heroHeight;
|
||||
int tileMaxY = std::max(details.start.y, details.end.y);
|
||||
|
||||
std::shared_ptr<CAnimation> animation = graphics->getAnimation(ho);
|
||||
|
||||
assert(animation);
|
||||
assert(animation->size(0) != 0);
|
||||
auto image = animation->getImage(0,0);
|
||||
|
||||
int heroImageOldX = details.start.x * 32;
|
||||
int heroImageOldY = details.start.y * 32;
|
||||
|
||||
int heroImageNewX = details.end.x * 32;
|
||||
int heroImageNewY = details.end.y * 32;
|
||||
|
||||
int heroImageCurrX = heroImageOldX + i*(heroImageNewX - heroImageOldX)/32;
|
||||
int heroImageCurrY = heroImageOldY + i*(heroImageNewY - heroImageOldY)/32;
|
||||
|
||||
// recompute which part of hero sprite will be visible on each tile at this point of movement animation
|
||||
for ( int tileX = tileMinX; tileX <= tileMaxX; ++tileX)
|
||||
{
|
||||
//setting advmap shift
|
||||
adventureInt->terrain.moveX = i-32;
|
||||
adventureInt->terrain.moveY = i-32;
|
||||
for ( int tileY = tileMinY; tileY <= tileMaxY; ++tileY)
|
||||
{
|
||||
auto & tile = subArr[tileX][tileY];
|
||||
for ( auto & obj : tile.objects)
|
||||
{
|
||||
if (obj.obj == ho)
|
||||
{
|
||||
int tilePosX = tileX * 32;
|
||||
int tilePosY = tileY * 32;
|
||||
|
||||
subRect(hp.x-3, hp.y-2, hp.z, genRect(32, 32, -31+i, -31+i), ho->id);
|
||||
subRect(hp.x-2, hp.y-2, hp.z, genRect(32, 32, 1+i, -31+i), ho->id);
|
||||
subRect(hp.x-1, hp.y-2, hp.z, genRect(32, 32, 33+i, -31+i), ho->id);
|
||||
subRect(hp.x, hp.y-2, hp.z, genRect(32, 32, 65+i, -31+i), ho->id);
|
||||
|
||||
subRect(hp.x-3, hp.y-1, hp.z, genRect(32, 32, -31+i, 1+i), ho->id);
|
||||
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, 1+i, 1+i), ho->id);
|
||||
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 33+i, 1+i), ho->id);
|
||||
subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 65+i, 1+i), ho->id);
|
||||
|
||||
subRect(hp.x-3, hp.y, hp.z, genRect(32, 32, -31+i, 33+i), ho->id);
|
||||
subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, 1+i, 33+i), ho->id);
|
||||
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 33+i, 33+i), ho->id);
|
||||
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 65+i, 33+i), ho->id);
|
||||
obj.rect.x = tilePosX - heroImageCurrX + image->width() - 32;
|
||||
obj.rect.y = tilePosY - heroImageCurrY + image->height() - 32;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (details.end.x == details.start.x && details.end.y+1 == details.start.y) //t
|
||||
{
|
||||
//setting advmap shift
|
||||
adventureInt->terrain.moveY = i-32;
|
||||
|
||||
subRect(hp.x-2, hp.y-2, hp.z, genRect(32, 32, 0, -31+i), ho->id);
|
||||
subRect(hp.x-1, hp.y-2, hp.z, genRect(32, 32, 32, -31+i), ho->id);
|
||||
subRect(hp.x, hp.y-2, hp.z, genRect(32, 32, 64, -31+i), ho->id);
|
||||
|
||||
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, 0, 1+i), ho->id);
|
||||
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 32, 1+i), ho->id);
|
||||
subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 64, 1+i), ho->id);
|
||||
|
||||
subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, 0, 33+i), ho->id);
|
||||
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 32, 33+i), ho->id);
|
||||
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 64, 33+i), ho->id);
|
||||
}
|
||||
else if (details.end.x-1 == details.start.x && details.end.y+1 == details.start.y) //tr
|
||||
{
|
||||
//setting advmap shift
|
||||
adventureInt->terrain.moveX = -i+32;
|
||||
adventureInt->terrain.moveY = i-32;
|
||||
|
||||
subRect(hp.x-2, hp.y-2, hp.z, genRect(32, 32, -1-i, -31+i), ho->id);
|
||||
subRect(hp.x-1, hp.y-2, hp.z, genRect(32, 32, 31-i, -31+i), ho->id);
|
||||
subRect(hp.x, hp.y-2, hp.z, genRect(32, 32, 63-i, -31+i), ho->id);
|
||||
subRect(hp.x+1, hp.y-2, hp.z, genRect(32, 32, 95-i, -31+i), ho->id);
|
||||
|
||||
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, -1-i, 1+i), ho->id);
|
||||
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 31-i, 1+i), ho->id);
|
||||
subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 63-i, 1+i), ho->id);
|
||||
subRect(hp.x+1, hp.y-1, hp.z, genRect(32, 32, 95-i, 1+i), ho->id);
|
||||
|
||||
subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, -1-i, 33+i), ho->id);
|
||||
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 31-i, 33+i), ho->id);
|
||||
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 63-i, 33+i), ho->id);
|
||||
subRect(hp.x+1, hp.y, hp.z, genRect(32, 32, 95-i, 33+i), ho->id);
|
||||
}
|
||||
else if (details.end.x-1 == details.start.x && details.end.y == details.start.y) //r
|
||||
{
|
||||
//setting advmap shift
|
||||
adventureInt->terrain.moveX = -i+32;
|
||||
|
||||
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, -1-i, 0), ho->id);
|
||||
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 31-i, 0), ho->id);
|
||||
subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 63-i, 0), ho->id);
|
||||
subRect(hp.x+1, hp.y-1, hp.z, genRect(32, 32, 95-i, 0), ho->id);
|
||||
|
||||
subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, -1-i, 32), ho->id);
|
||||
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 31-i, 32), ho->id);
|
||||
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 63-i, 32), ho->id);
|
||||
subRect(hp.x+1, hp.y, hp.z, genRect(32, 32, 95-i, 32), ho->id);
|
||||
}
|
||||
else if (details.end.x-1 == details.start.x && details.end.y-1 == details.start.y) //br
|
||||
{
|
||||
|
||||
//setting advmap shift
|
||||
adventureInt->terrain.moveX = -i+32;
|
||||
adventureInt->terrain.moveY = -i+32;
|
||||
|
||||
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, -1-i, -1-i), ho->id);
|
||||
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 31-i, -1-i), ho->id);
|
||||
subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 63-i, -1-i), ho->id);
|
||||
subRect(hp.x+1, hp.y-1, hp.z, genRect(32, 32, 95-i, -1-i), ho->id);
|
||||
|
||||
subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, -1-i, 31-i), ho->id);
|
||||
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 31-i, 31-i), ho->id);
|
||||
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 63-i, 31-i), ho->id);
|
||||
subRect(hp.x+1, hp.y, hp.z, genRect(32, 32, 95-i, 31-i), ho->id);
|
||||
|
||||
subRect(hp.x-2, hp.y+1, hp.z, genRect(32, 32, -1-i, 63-i), ho->id);
|
||||
subRect(hp.x-1, hp.y+1, hp.z, genRect(32, 32, 31-i, 63-i), ho->id);
|
||||
subRect(hp.x, hp.y+1, hp.z, genRect(32, 32, 63-i, 63-i), ho->id);
|
||||
subRect(hp.x+1, hp.y+1, hp.z, genRect(32, 32, 95-i, 63-i), ho->id);
|
||||
}
|
||||
else if (details.end.x == details.start.x && details.end.y-1 == details.start.y) //b
|
||||
{
|
||||
//setting advmap shift
|
||||
adventureInt->terrain.moveY = -i+32;
|
||||
|
||||
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, 0, -1-i), ho->id);
|
||||
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 32, -1-i), ho->id);
|
||||
subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 64, -1-i), ho->id);
|
||||
|
||||
subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, 0, 31-i), ho->id);
|
||||
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 32, 31-i), ho->id);
|
||||
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 64, 31-i), ho->id);
|
||||
|
||||
subRect(hp.x-2, hp.y+1, hp.z, genRect(32, 32, 0, 63-i), ho->id);
|
||||
subRect(hp.x-1, hp.y+1, hp.z, genRect(32, 32, 32, 63-i), ho->id);
|
||||
subRect(hp.x, hp.y+1, hp.z, genRect(32, 32, 64, 63-i), ho->id);
|
||||
}
|
||||
else if (details.end.x+1 == details.start.x && details.end.y-1 == details.start.y) //bl
|
||||
{
|
||||
//setting advmap shift
|
||||
adventureInt->terrain.moveX = i-32;
|
||||
adventureInt->terrain.moveY = -i+32;
|
||||
|
||||
subRect(hp.x-3, hp.y-1, hp.z, genRect(32, 32, -31+i, -1-i), ho->id);
|
||||
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, 1+i, -1-i), ho->id);
|
||||
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 33+i, -1-i), ho->id);
|
||||
subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 65+i, -1-i), ho->id);
|
||||
|
||||
subRect(hp.x-3, hp.y, hp.z, genRect(32, 32, -31+i, 31-i), ho->id);
|
||||
subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, 1+i, 31-i), ho->id);
|
||||
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 33+i, 31-i), ho->id);
|
||||
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 65+i, 31-i), ho->id);
|
||||
|
||||
subRect(hp.x-3, hp.y+1, hp.z, genRect(32, 32, -31+i, 63-i), ho->id);
|
||||
subRect(hp.x-2, hp.y+1, hp.z, genRect(32, 32, 1+i, 63-i), ho->id);
|
||||
subRect(hp.x-1, hp.y+1, hp.z, genRect(32, 32, 33+i, 63-i), ho->id);
|
||||
subRect(hp.x, hp.y+1, hp.z, genRect(32, 32, 65+i, 63-i), ho->id);
|
||||
}
|
||||
else if (details.end.x+1 == details.start.x && details.end.y == details.start.y) //l
|
||||
{
|
||||
//setting advmap shift
|
||||
adventureInt->terrain.moveX = i-32;
|
||||
|
||||
subRect(hp.x-3, hp.y-1, hp.z, genRect(32, 32, -31+i, 0), ho->id);
|
||||
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, 1+i, 0), ho->id);
|
||||
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 33+i, 0), ho->id);
|
||||
subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 65+i, 0), ho->id);
|
||||
|
||||
subRect(hp.x-3, hp.y, hp.z, genRect(32, 32, -31+i, 32), ho->id);
|
||||
subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, 1+i, 32), ho->id);
|
||||
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 33+i, 32), ho->id);
|
||||
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 65+i, 32), ho->id);
|
||||
}
|
||||
adventureInt->terrain.moveX = (32 - i) * (heroImageNewX - heroImageOldX) / 32;
|
||||
adventureInt->terrain.moveY = (32 - i) * (heroImageNewY - heroImageOldY) / 32;
|
||||
}
|
||||
|
||||
void CPlayerInterface::finishMovement( const TryMoveHero &details, const int3 &hp, const CGHeroInstance * ho )
|
||||
{
|
||||
adventureInt->terrain.moveX = adventureInt->terrain.moveY = 0;
|
||||
auto subArr = (CGI->mh->ttiles)[hp.z];
|
||||
|
||||
if (details.end.x+1 == details.start.x && details.end.y+1 == details.start.y) //tl
|
||||
int heroWidth = ho->appearance->getWidth();
|
||||
int heroHeight = ho->appearance->getHeight();
|
||||
|
||||
int tileMinX = std::min(details.start.x, details.end.x) - heroWidth;
|
||||
int tileMaxX = std::max(details.start.x, details.end.x);
|
||||
int tileMinY = std::min(details.start.y, details.end.y) - heroHeight;
|
||||
int tileMaxY = std::max(details.start.y, details.end.y);
|
||||
|
||||
// erase hero from all tiles on which he is currently visible
|
||||
for ( int tileX = tileMinX; tileX <= tileMaxX; ++tileX)
|
||||
{
|
||||
delObjRect(hp.x, hp.y-2, hp.z, ho->id);
|
||||
delObjRect(hp.x, hp.y-1, hp.z, ho->id);
|
||||
delObjRect(hp.x, hp.y, hp.z, ho->id);
|
||||
delObjRect(hp.x-1, hp.y, hp.z, ho->id);
|
||||
delObjRect(hp.x-2, hp.y, hp.z, ho->id);
|
||||
delObjRect(hp.x-3, hp.y, hp.z, ho->id);
|
||||
}
|
||||
else if (details.end.x == details.start.x && details.end.y+1 == details.start.y) //t
|
||||
{
|
||||
delObjRect(hp.x, hp.y, hp.z, ho->id);
|
||||
delObjRect(hp.x-1, hp.y, hp.z, ho->id);
|
||||
delObjRect(hp.x-2, hp.y, hp.z, ho->id);
|
||||
}
|
||||
else if (details.end.x-1 == details.start.x && details.end.y+1 == details.start.y) //tr
|
||||
{
|
||||
delObjRect(hp.x-2, hp.y-2, hp.z, ho->id);
|
||||
delObjRect(hp.x-2, hp.y-1, hp.z, ho->id);
|
||||
delObjRect(hp.x+1, hp.y, hp.z, ho->id);
|
||||
delObjRect(hp.x, hp.y, hp.z, ho->id);
|
||||
delObjRect(hp.x-1, hp.y, hp.z, ho->id);
|
||||
delObjRect(hp.x-2, hp.y, hp.z, ho->id);
|
||||
}
|
||||
else if (details.end.x-1 == details.start.x && details.end.y == details.start.y) //r
|
||||
{
|
||||
delObjRect(hp.x-2, hp.y-1, hp.z, ho->id);
|
||||
delObjRect(hp.x-2, hp.y, hp.z, ho->id);
|
||||
}
|
||||
else if (details.end.x-1 == details.start.x && details.end.y-1 == details.start.y) //br
|
||||
{
|
||||
delObjRect(hp.x-2, hp.y+1, hp.z, ho->id);
|
||||
delObjRect(hp.x-2, hp.y, hp.z, ho->id);
|
||||
delObjRect(hp.x+1, hp.y-1, hp.z, ho->id);
|
||||
delObjRect(hp.x, hp.y-1, hp.z, ho->id);
|
||||
delObjRect(hp.x-1, hp.y-1, hp.z, ho->id);
|
||||
delObjRect(hp.x-2, hp.y-1, hp.z, ho->id);
|
||||
}
|
||||
else if (details.end.x == details.start.x && details.end.y-1 == details.start.y) //b
|
||||
{
|
||||
delObjRect(hp.x, hp.y-1, hp.z, ho->id);
|
||||
delObjRect(hp.x-1, hp.y-1, hp.z, ho->id);
|
||||
delObjRect(hp.x-2, hp.y-1, hp.z, ho->id);
|
||||
}
|
||||
else if (details.end.x+1 == details.start.x && details.end.y-1 == details.start.y) //bl
|
||||
{
|
||||
delObjRect(hp.x, hp.y-1, hp.z, ho->id);
|
||||
delObjRect(hp.x-1, hp.y-1, hp.z, ho->id);
|
||||
delObjRect(hp.x-2, hp.y-1, hp.z, ho->id);
|
||||
delObjRect(hp.x-3, hp.y-1, hp.z, ho->id);
|
||||
delObjRect(hp.x, hp.y, hp.z, ho->id);
|
||||
delObjRect(hp.x, hp.y+1, hp.z, ho->id);
|
||||
}
|
||||
else if (details.end.x+1 == details.start.x && details.end.y == details.start.y) //l
|
||||
{
|
||||
delObjRect(hp.x, hp.y-1, hp.z, ho->id);
|
||||
delObjRect(hp.x, hp.y, hp.z, ho->id);
|
||||
for ( int tileY = tileMinY; tileY <= tileMaxY; ++tileY)
|
||||
{
|
||||
auto & tile = subArr[tileX][tileY];
|
||||
for (size_t i = 0; i < tile.objects.size(); ++i)
|
||||
{
|
||||
if ( tile.objects[i].obj == ho)
|
||||
{
|
||||
tile.objects.erase(tile.objects.begin() + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//restoring good rects
|
||||
subRect(details.end.x-2, details.end.y-1, details.end.z, genRect(32, 32, 0, 0), ho->id);
|
||||
subRect(details.end.x-1, details.end.y-1, details.end.z, genRect(32, 32, 32, 0), ho->id);
|
||||
subRect(details.end.x, details.end.y-1, details.end.z, genRect(32, 32, 64, 0), ho->id);
|
||||
// re-add hero to all tiles on which he will still be visible after animation is over
|
||||
for ( int tileX = details.end.x - heroWidth + 1; tileX <= details.end.x; ++tileX)
|
||||
{
|
||||
for ( int tileY = details.end.y - heroHeight + 1; tileY <= details.end.y; ++tileY)
|
||||
{
|
||||
auto & tile = subArr[tileX][tileY];
|
||||
tile.objects.push_back(TerrainTileObject(ho, {0,0,32,32}));
|
||||
}
|
||||
}
|
||||
|
||||
subRect(details.end.x-2, details.end.y, details.end.z, genRect(32, 32, 0, 32), ho->id);
|
||||
subRect(details.end.x-1, details.end.y, details.end.z, genRect(32, 32, 32, 32), ho->id);
|
||||
subRect(details.end.x, details.end.y, details.end.z, genRect(32, 32, 64, 32), ho->id);
|
||||
// update object list on all tiles that were affected during previous operations
|
||||
for ( int tileX = tileMinX; tileX <= tileMaxX; ++tileX)
|
||||
{
|
||||
for ( int tileY = tileMinY; tileY <= tileMaxY; ++tileY)
|
||||
{
|
||||
auto & tile = subArr[tileX][tileY];
|
||||
std::stable_sort(tile.objects.begin(), tile.objects.end(), objectBlitOrderSorter);
|
||||
}
|
||||
}
|
||||
|
||||
//restoring good order of objects
|
||||
|
||||
boost::detail::multi_array::sub_array<TerrainTile2, 2> subArr = (CGI->mh->ttiles)[details.end.z];
|
||||
|
||||
std::stable_sort(subArr[details.end.x-2][details.end.y-1].objects.begin(), subArr[details.end.x-2][details.end.y-1].objects.end(), objectBlitOrderSorter);
|
||||
std::stable_sort(subArr[details.end.x-1][details.end.y-1].objects.begin(), subArr[details.end.x-1][details.end.y-1].objects.end(), objectBlitOrderSorter);
|
||||
std::stable_sort(subArr[details.end.x][details.end.y-1].objects.begin(), subArr[details.end.x][details.end.y-1].objects.end(), objectBlitOrderSorter);
|
||||
|
||||
std::stable_sort(subArr[details.end.x-2][details.end.y].objects.begin(), subArr[details.end.x-2][details.end.y].objects.end(), objectBlitOrderSorter);
|
||||
std::stable_sort(subArr[details.end.x-1][details.end.y].objects.begin(), subArr[details.end.x-1][details.end.y].objects.end(), objectBlitOrderSorter);
|
||||
std::stable_sort(subArr[details.end.x][details.end.y].objects.begin(), subArr[details.end.x][details.end.y].objects.end(), objectBlitOrderSorter);
|
||||
//recompute hero sprite positioning using hero's final position
|
||||
movementPxStep(details, 32, hp, ho);
|
||||
}
|
||||
|
||||
void CPlayerInterface::gameOver(PlayerColor player, const EVictoryLossCheckResult & victoryLossCheckResult )
|
||||
|
@ -785,22 +785,25 @@ bool CShootingAnimation::init()
|
||||
if (projectileAngle > straightAngle)
|
||||
{
|
||||
//upper shot
|
||||
spi.x = fromPos.x + 222 + ( -25 + shooterInfo->animation.upperRightMissleOffsetX ) * multiplier;
|
||||
spi.y = fromPos.y + 265 + shooterInfo->animation.upperRightMissleOffsetY;
|
||||
spi.x0 = fromPos.x + 222 + ( -25 + shooterInfo->animation.upperRightMissleOffsetX ) * multiplier;
|
||||
spi.y0 = fromPos.y + 265 + shooterInfo->animation.upperRightMissleOffsetY;
|
||||
}
|
||||
else if (projectileAngle < -straightAngle)
|
||||
{
|
||||
//lower shot
|
||||
spi.x = fromPos.x + 222 + ( -25 + shooterInfo->animation.lowerRightMissleOffsetX ) * multiplier;
|
||||
spi.y = fromPos.y + 265 + shooterInfo->animation.lowerRightMissleOffsetY;
|
||||
spi.x0 = fromPos.x + 222 + ( -25 + shooterInfo->animation.lowerRightMissleOffsetX ) * multiplier;
|
||||
spi.y0 = fromPos.y + 265 + shooterInfo->animation.lowerRightMissleOffsetY;
|
||||
}
|
||||
else
|
||||
{
|
||||
//straight shot
|
||||
spi.x = fromPos.x + 222 + ( -25 + shooterInfo->animation.rightMissleOffsetX ) * multiplier;
|
||||
spi.y = fromPos.y + 265 + shooterInfo->animation.rightMissleOffsetY;
|
||||
spi.x0 = fromPos.x + 222 + ( -25 + shooterInfo->animation.rightMissleOffsetX ) * multiplier;
|
||||
spi.y0 = fromPos.y + 265 + shooterInfo->animation.rightMissleOffsetY;
|
||||
}
|
||||
|
||||
spi.x = spi.x0;
|
||||
spi.y = spi.y0;
|
||||
|
||||
destPos += Point(225, 225);
|
||||
|
||||
// recalculate angle taking in account offsets
|
||||
@ -811,7 +814,9 @@ bool CShootingAnimation::init()
|
||||
if (attackedStack)
|
||||
{
|
||||
double animSpeed = AnimationControls::getProjectileSpeed(); // flight speed of projectile
|
||||
spi.lastStep = static_cast<int>(sqrt(static_cast<double>((destPos.x - spi.x) * (destPos.x - spi.x) + (destPos.y - spi.y) * (destPos.y - spi.y))) / animSpeed);
|
||||
double distanceSquared = (destPos.x - spi.x) * (destPos.x - spi.x) + (destPos.y - spi.y) * (destPos.y - spi.y);
|
||||
double distance = sqrt(distanceSquared);
|
||||
spi.lastStep = std::round(distance / animSpeed);
|
||||
if(spi.lastStep == 0)
|
||||
spi.lastStep = 1;
|
||||
spi.dx = (destPos.x - spi.x) / spi.lastStep;
|
||||
@ -837,30 +842,42 @@ bool CShootingAnimation::init()
|
||||
}
|
||||
double pi = boost::math::constants::pi<double>();
|
||||
|
||||
if (owner->idToProjectile.count(spi.creID) == 0) //in some cases (known one: hero grants shooter bonus to unit) the shooter stack's projectile may not be properly initialized
|
||||
//in some cases (known one: hero grants shooter bonus to unit) the shooter stack's projectile may not be properly initialized
|
||||
if (!owner->idToProjectile.count(spi.creID) && !owner->idToRay.count(spi.creID))
|
||||
owner->initStackProjectile(shooter);
|
||||
|
||||
// only frames below maxFrame are usable: anything higher is either no present or we don't know when it should be used
|
||||
size_t maxFrame = std::min<size_t>(angles.size(), owner->idToProjectile.at(spi.creID)->size(0));
|
||||
|
||||
assert(maxFrame > 0);
|
||||
|
||||
// values in angles array indicate position from which this frame was rendered, in degrees.
|
||||
// find frame that has closest angle to one that we need for this shot
|
||||
size_t bestID = 0;
|
||||
double bestDiff = fabs( angles[0] / 180 * pi - projectileAngle );
|
||||
|
||||
for (size_t i=1; i<maxFrame; i++)
|
||||
if (owner->idToProjectile.count(spi.creID))
|
||||
{
|
||||
double currentDiff = fabs( angles[i] / 180 * pi - projectileAngle );
|
||||
if (currentDiff < bestDiff)
|
||||
{
|
||||
bestID = i;
|
||||
bestDiff = currentDiff;
|
||||
}
|
||||
}
|
||||
// only frames below maxFrame are usable: anything higher is either no present or we don't know when it should be used
|
||||
size_t maxFrame = std::min<size_t>(angles.size(), owner->idToProjectile.at(spi.creID)->size(0));
|
||||
|
||||
spi.frameNum = static_cast<int>(bestID);
|
||||
assert(maxFrame > 0);
|
||||
|
||||
// values in angles array indicate position from which this frame was rendered, in degrees.
|
||||
// find frame that has closest angle to one that we need for this shot
|
||||
size_t bestID = 0;
|
||||
double bestDiff = fabs( angles[0] / 180 * pi - projectileAngle );
|
||||
|
||||
for (size_t i=1; i<maxFrame; i++)
|
||||
{
|
||||
double currentDiff = fabs( angles[i] / 180 * pi - projectileAngle );
|
||||
if (currentDiff < bestDiff)
|
||||
{
|
||||
bestID = i;
|
||||
bestDiff = currentDiff;
|
||||
}
|
||||
}
|
||||
|
||||
spi.frameNum = static_cast<int>(bestID);
|
||||
}
|
||||
else if (owner->idToRay.count(spi.creID))
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
else
|
||||
{
|
||||
logGlobal->error("Unable to find valid projectile for shooter %d", spi.creID);
|
||||
}
|
||||
|
||||
// Set projectile animation start delay which is specified in frames
|
||||
spi.animStartDelay = shooterInfo->animation.attackClimaxFrame;
|
||||
|
@ -189,6 +189,7 @@ public:
|
||||
/// Small struct which contains information about the position and the velocity of a projectile
|
||||
struct ProjectileInfo
|
||||
{
|
||||
double x0, y0; //initial position on the screen
|
||||
double x, y; //position on the screen
|
||||
double dx, dy; //change in position in one step
|
||||
int step, lastStep; //to know when finish showing this projectile
|
||||
|
@ -1020,15 +1020,22 @@ void CBattleInterface::initStackProjectile(const CStack * stack)
|
||||
else
|
||||
creature = stack->getCreature();
|
||||
|
||||
std::shared_ptr<CAnimation> projectile = std::make_shared<CAnimation>(creature->animation.projectileImageName);
|
||||
projectile->preload();
|
||||
if (creature->animation.projectileRay.empty())
|
||||
{
|
||||
std::shared_ptr<CAnimation> projectile = std::make_shared<CAnimation>(creature->animation.projectileImageName);
|
||||
projectile->preload();
|
||||
|
||||
if(projectile->size(1) != 0)
|
||||
logAnim->error("Expected empty group 1 in stack projectile");
|
||||
if(projectile->size(1) != 0)
|
||||
logAnim->error("Expected empty group 1 in stack projectile");
|
||||
else
|
||||
projectile->createFlippedGroup(0, 1);
|
||||
|
||||
idToProjectile[stack->getCreature()->idNumber] = projectile;
|
||||
}
|
||||
else
|
||||
projectile->createFlippedGroup(0, 1);
|
||||
|
||||
idToProjectile[stack->getCreature()->idNumber] = projectile;
|
||||
{
|
||||
idToRay[stack->getCreature()->idNumber] = creature->animation.projectileRay;
|
||||
}
|
||||
}
|
||||
|
||||
void CBattleInterface::stackRemoved(uint32_t stackID)
|
||||
@ -3206,23 +3213,63 @@ void CBattleInterface::showProjectiles(SDL_Surface *to)
|
||||
continue; // wait...
|
||||
}
|
||||
|
||||
size_t group = it->reverse ? 1 : 0;
|
||||
auto image = idToProjectile[it->creID]->getImage(it->frameNum, group, true);
|
||||
|
||||
if(image)
|
||||
if (idToProjectile.count(it->creID))
|
||||
{
|
||||
SDL_Rect dst;
|
||||
dst.h = image->height();
|
||||
dst.w = image->width();
|
||||
dst.x = static_cast<int>(it->x - dst.w / 2);
|
||||
dst.y = static_cast<int>(it->y - dst.h / 2);
|
||||
size_t group = it->reverse ? 1 : 0;
|
||||
auto image = idToProjectile[it->creID]->getImage(it->frameNum, group, true);
|
||||
|
||||
image->draw(to, &dst, nullptr);
|
||||
if(image)
|
||||
{
|
||||
SDL_Rect dst;
|
||||
dst.h = image->height();
|
||||
dst.w = image->width();
|
||||
dst.x = static_cast<int>(it->x - dst.w / 2);
|
||||
dst.y = static_cast<int>(it->y - dst.h / 2);
|
||||
|
||||
image->draw(to, &dst, nullptr);
|
||||
}
|
||||
}
|
||||
if (idToRay.count(it->creID))
|
||||
{
|
||||
auto const & ray = idToRay[it->creID];
|
||||
|
||||
if (std::abs(it->dx) > std::abs(it->dy)) // draw in horizontal axis
|
||||
{
|
||||
int y1 = it->y0 - ray.size() / 2;
|
||||
int y2 = it->y - ray.size() / 2;
|
||||
|
||||
int x1 = it->x0;
|
||||
int x2 = it->x;
|
||||
|
||||
for (size_t i = 0; i < ray.size(); ++i)
|
||||
{
|
||||
SDL_Color beginColor{ ray[i].r1, ray[i].g1, ray[i].b1, ray[i].a1};
|
||||
SDL_Color endColor { ray[i].r2, ray[i].g2, ray[i].b2, ray[i].a2};
|
||||
|
||||
CSDL_Ext::drawLine(to, x1, y1 + i, x2, y2 + i, beginColor, endColor);
|
||||
}
|
||||
}
|
||||
else // draw in vertical axis
|
||||
{
|
||||
int x1 = it->x0 - ray.size() / 2;
|
||||
int x2 = it->x - ray.size() / 2;
|
||||
|
||||
int y1 = it->y0;
|
||||
int y2 = it->y;
|
||||
|
||||
for (size_t i = 0; i < ray.size(); ++i)
|
||||
{
|
||||
SDL_Color beginColor{ ray[i].r1, ray[i].g1, ray[i].b1, ray[i].a1};
|
||||
SDL_Color endColor { ray[i].r2, ray[i].g2, ray[i].b2, ray[i].a2};
|
||||
|
||||
CSDL_Ext::drawLine(to, x1 + i, y1, x2 + i, y2, beginColor, endColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update projectile
|
||||
++it->step;
|
||||
if (it->step == it->lastStep)
|
||||
if (it->step > it->lastStep)
|
||||
{
|
||||
toBeDeleted.insert(toBeDeleted.end(), it);
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "CBattleAnimations.h"
|
||||
|
||||
#include "../../lib/spells/CSpellHandler.h" //CSpell::TAnimation
|
||||
#include "../../lib/CCreatureHandler.h"
|
||||
#include "../../lib/battle/CBattleInfoCallback.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
@ -148,6 +149,7 @@ private:
|
||||
std::map<int32_t, std::shared_ptr<CCreatureAnimation>> creAnims; //animations of creatures from fighting armies (order by BattleInfo's stacks' ID)
|
||||
|
||||
std::map<int, std::shared_ptr<CAnimation>> idToProjectile;
|
||||
std::map<int, std::vector<CCreature::CreatureAnimation::RayColor>> idToRay;
|
||||
|
||||
std::map<std::string, std::shared_ptr<CAnimation>> animationsCache;
|
||||
std::map<si32, std::shared_ptr<CAnimation>> obstacleAnimations;
|
||||
|
@ -361,6 +361,75 @@ void CSDL_Ext::update(SDL_Surface * what)
|
||||
if(0 !=SDL_UpdateTexture(screenTexture, nullptr, what->pixels, what->pitch))
|
||||
logGlobal->error("%s SDL_UpdateTexture %s", __FUNCTION__, SDL_GetError());
|
||||
}
|
||||
|
||||
template<typename Int>
|
||||
Int lerp(Int a, Int b, float f)
|
||||
{
|
||||
return a + std::round((b - a) * f);
|
||||
}
|
||||
|
||||
static void drawLineX(SDL_Surface * sur, int x1, int y1, int x2, int y2, const SDL_Color & color1, const SDL_Color & color2)
|
||||
{
|
||||
for(int x = x1; x <= x2; x++)
|
||||
{
|
||||
float f = float(x - x1) / float(x2 - x1);
|
||||
int y = lerp(y1, y2, f);
|
||||
|
||||
uint8_t r = lerp(color1.r, color2.r, f);
|
||||
uint8_t g = lerp(color1.g, color2.g, f);
|
||||
uint8_t b = lerp(color1.b, color2.b, f);
|
||||
uint8_t a = lerp(color1.a, color2.a, f);
|
||||
|
||||
Uint8 *p = CSDL_Ext::getPxPtr(sur, x, y);
|
||||
ColorPutter<4, 0>::PutColor(p, r,g,b,a);
|
||||
}
|
||||
}
|
||||
|
||||
static void drawLineY(SDL_Surface * sur, int x1, int y1, int x2, int y2, const SDL_Color & color1, const SDL_Color & color2)
|
||||
{
|
||||
for(int y = y1; y <= y2; y++)
|
||||
{
|
||||
float f = float(y - y1) / float(y2 - y1);
|
||||
int x = lerp(x1, x2, f);
|
||||
|
||||
uint8_t r = lerp(color1.r, color2.r, f);
|
||||
uint8_t g = lerp(color1.g, color2.g, f);
|
||||
uint8_t b = lerp(color1.b, color2.b, f);
|
||||
uint8_t a = lerp(color1.a, color2.a, f);
|
||||
|
||||
Uint8 *p = CSDL_Ext::getPxPtr(sur, x, y);
|
||||
ColorPutter<4, 0>::PutColor(p, r,g,b,a);
|
||||
}
|
||||
}
|
||||
|
||||
void CSDL_Ext::drawLine(SDL_Surface * sur, int x1, int y1, int x2, int y2, const SDL_Color & color1, const SDL_Color & color2)
|
||||
{
|
||||
int width = std::abs(x1-x2);
|
||||
int height = std::abs(y1-y2);
|
||||
|
||||
if ( width == 0 && height == 0)
|
||||
{
|
||||
Uint8 *p = CSDL_Ext::getPxPtr(sur, x1, y1);
|
||||
ColorPutter<4, 0>::PutColorAlpha(p, color1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (width > height)
|
||||
{
|
||||
if ( x1 < x2)
|
||||
drawLineX(sur, x1,y1,x2,y2, color1, color2);
|
||||
else
|
||||
drawLineX(sur, x2,y2,x1,y1, color2, color1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( y1 < y2)
|
||||
drawLineY(sur, x1,y1,x2,y2, color1, color2);
|
||||
else
|
||||
drawLineY(sur, x2,y2,x1,y1, color2, color1);
|
||||
}
|
||||
}
|
||||
|
||||
void CSDL_Ext::drawBorder(SDL_Surface * sur, int x, int y, int w, int h, const int3 &color)
|
||||
{
|
||||
for(int i = 0; i < w; i++)
|
||||
|
@ -236,6 +236,7 @@ namespace CSDL_Ext
|
||||
SDL_Color makeColor(ui8 r, ui8 g, ui8 b, ui8 a);
|
||||
|
||||
void update(SDL_Surface * what = screen); //updates whole surface (default - main screen)
|
||||
void drawLine(SDL_Surface * sur, int x1, int y1, int x2, int y2, const SDL_Color & color1, const SDL_Color & color2);
|
||||
void drawBorder(SDL_Surface * sur, int x, int y, int w, int h, const int3 &color);
|
||||
void drawBorder(SDL_Surface * sur, const SDL_Rect &r, const int3 &color);
|
||||
void drawDashedBorder(SDL_Surface * sur, const Rect &r, const int3 &color);
|
||||
|
@ -107,6 +107,10 @@ RandomMapTab::RandomMapTab()
|
||||
groupCompOnlyPlayers->addCallback([&](int btnId)
|
||||
{
|
||||
mapGenOptions->setCompOnlyPlayerCount(btnId);
|
||||
|
||||
// deactive some MaxPlayers buttons to prevent total number of players exceeds PlayerColor::PLAYER_LIMIT_I
|
||||
deactivateButtonsFrom(groupMaxPlayers.get(), PlayerColor::PLAYER_LIMIT_I - btnId + 1);
|
||||
|
||||
deactivateButtonsFrom(groupCompOnlyTeams.get(), (btnId == 0 ? 1 : btnId));
|
||||
validateCompOnlyPlayersCnt(btnId);
|
||||
updateMapInfoByHost();
|
||||
|
@ -135,7 +135,14 @@
|
||||
"animation": "CBEHOL.DEF",
|
||||
"missile" :
|
||||
{
|
||||
"projectile": "SMBALX.DEF"
|
||||
"ray" :
|
||||
[
|
||||
{ "start" : [ 160, 160, 160, 255 ], "end" : [ 160, 160, 160, 64 ] },
|
||||
{ "start" : [ 192, 192, 192, 255 ], "end" : [ 192, 192, 192, 128 ] },
|
||||
{ "start" : [ 224, 224, 224, 255 ], "end" : [ 224, 224, 224, 255 ] },
|
||||
{ "start" : [ 192, 192, 192, 255 ], "end" : [ 192, 192, 192, 128 ] },
|
||||
{ "start" : [ 160, 160, 160, 255 ], "end" : [ 160, 160, 160, 64 ] }
|
||||
]
|
||||
}
|
||||
},
|
||||
"sound" :
|
||||
@ -158,7 +165,14 @@
|
||||
"animation": "CEVEYE.DEF",
|
||||
"missile" :
|
||||
{
|
||||
"projectile": "SMBALX.DEF"
|
||||
"ray" :
|
||||
[
|
||||
{ "start" : [ 160, 160, 160, 255 ], "end" : [ 160, 160, 160, 64 ] },
|
||||
{ "start" : [ 192, 192, 192, 255 ], "end" : [ 192, 192, 192, 128 ] },
|
||||
{ "start" : [ 224, 224, 224, 255 ], "end" : [ 224, 224, 224, 255 ] },
|
||||
{ "start" : [ 192, 192, 192, 255 ], "end" : [ 192, 192, 192, 128 ] },
|
||||
{ "start" : [ 160, 160, 160, 255 ], "end" : [ 160, 160, 160, 64 ] }
|
||||
]
|
||||
}
|
||||
},
|
||||
"sound" :
|
||||
|
@ -208,7 +208,15 @@
|
||||
"animation": "CAMAGE.DEF",
|
||||
"missile" :
|
||||
{
|
||||
"projectile": "PMAGEX.DEF"
|
||||
"attackClimaxFrame" : 8,
|
||||
"ray" :
|
||||
[
|
||||
{ "start" : [ 160, 192, 0, 255 ], "end" : [ 160, 192, 0, 64 ] },
|
||||
{ "start" : [ 128, 224, 128, 255 ], "end" : [ 128, 224, 128, 128 ] },
|
||||
{ "start" : [ 32, 176, 32, 255 ], "end" : [ 32, 176, 32, 255 ] },
|
||||
{ "start" : [ 128, 224, 128, 255 ], "end" : [ 128, 224, 128, 128 ] },
|
||||
{ "start" : [ 160, 192, 0, 255 ], "end" : [ 160, 192, 0, 64 ] }
|
||||
]
|
||||
}
|
||||
},
|
||||
"sound" :
|
||||
|
@ -27,7 +27,7 @@
|
||||
"base" : {
|
||||
"base" : {
|
||||
"visitableFrom" : [ "+++", "+-+", "+++" ],
|
||||
"mask" : [ "VV", "AV"]
|
||||
"mask" : [ "VVV", "VAV"]
|
||||
},
|
||||
"sounds" : {
|
||||
"removal" : ["KILLFADE"]
|
||||
|
@ -217,7 +217,7 @@
|
||||
"missile": {
|
||||
"type":"object",
|
||||
"additionalProperties" : false,
|
||||
"required" : [ "projectile", "frameAngles", "offset", "attackClimaxFrame" ],
|
||||
"required" : [ "frameAngles", "offset", "attackClimaxFrame" ],
|
||||
"description": "Missile description for archers",
|
||||
"properties":{
|
||||
"projectile": {
|
||||
@ -225,6 +225,37 @@
|
||||
"description": "Path to projectile animation",
|
||||
"format" : "defFile"
|
||||
},
|
||||
"ray": {
|
||||
"type":"array",
|
||||
"description": "Colors of ray projectile animation",
|
||||
"minItems" : 1,
|
||||
"items": {
|
||||
"type":"object",
|
||||
"required" : [ "start", "end" ],
|
||||
"properties":{
|
||||
"start": {
|
||||
"type":"array",
|
||||
"minItems" : 4,
|
||||
"maxItems" : 4,
|
||||
"items": {
|
||||
"minimum" : 0,
|
||||
"maximum" : 255,
|
||||
"type":"number"
|
||||
}
|
||||
},
|
||||
"end": {
|
||||
"type":"array",
|
||||
"minItems" : 4,
|
||||
"maxItems" : 4,
|
||||
"items": {
|
||||
"minimum" : 0,
|
||||
"maximum" : 255,
|
||||
"type":"number"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"frameAngles": {
|
||||
"type":"array",
|
||||
"description": "Angles of missile images, should go from 90 to -90",
|
||||
|
@ -907,6 +907,23 @@ void CCreatureHandler::loadCreatureJson(CCreature * creature, const JsonNode & c
|
||||
|
||||
creature->animation.projectileImageName = config["graphics"]["missile"]["projectile"].String();
|
||||
|
||||
for(const JsonNode & value : config["graphics"]["missile"]["ray"].Vector())
|
||||
{
|
||||
CCreature::CreatureAnimation::RayColor color;
|
||||
|
||||
color.r1 = value["start"].Vector()[0].Integer();
|
||||
color.g1 = value["start"].Vector()[1].Integer();
|
||||
color.b1 = value["start"].Vector()[2].Integer();
|
||||
color.a1 = value["start"].Vector()[3].Integer();
|
||||
|
||||
color.r2 = value["end"].Vector()[0].Integer();
|
||||
color.g2 = value["end"].Vector()[1].Integer();
|
||||
color.b2 = value["end"].Vector()[2].Integer();
|
||||
color.a2 = value["end"].Vector()[3].Integer();
|
||||
|
||||
creature->animation.projectileRay.push_back(color);
|
||||
}
|
||||
|
||||
creature->special = config["special"].Bool() || config["disabled"].Bool();
|
||||
|
||||
const JsonNode & sounds = config["sound"];
|
||||
|
@ -63,6 +63,16 @@ public:
|
||||
|
||||
struct CreatureAnimation
|
||||
{
|
||||
struct RayColor {
|
||||
uint8_t r1, g1, b1, a1;
|
||||
uint8_t r2, g2, b2, a2;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & r1 & g1 & b1 & a1 & r2 & g2 & b2 & a2;
|
||||
}
|
||||
};
|
||||
|
||||
double timeBetweenFidgets, idleAnimationTime,
|
||||
walkAnimationTime, attackAnimationTime, flightAnimationDistance;
|
||||
int upperRightMissleOffsetX, rightMissleOffsetX, lowerRightMissleOffsetX,
|
||||
@ -72,6 +82,7 @@ public:
|
||||
int troopCountLocationOffset, attackClimaxFrame;
|
||||
|
||||
std::string projectileImageName;
|
||||
std::vector<RayColor> projectileRay;
|
||||
//bool projectileSpin; //if true, appropriate projectile is spinning during flight
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
@ -91,6 +102,7 @@ public:
|
||||
h & troopCountLocationOffset;
|
||||
h & attackClimaxFrame;
|
||||
h & projectileImageName;
|
||||
h & projectileRay;
|
||||
}
|
||||
} animation;
|
||||
|
||||
|
@ -70,7 +70,7 @@ void CMapGenOptions::setPlayerCount(si8 value)
|
||||
assert((value >= 1 && value <= PlayerColor::PLAYER_LIMIT_I) || value == RANDOM_SIZE);
|
||||
playerCount = value;
|
||||
|
||||
auto possibleCompPlayersCount = value;
|
||||
auto possibleCompPlayersCount = PlayerColor::PLAYER_LIMIT_I - value;
|
||||
if (compOnlyPlayerCount > possibleCompPlayersCount)
|
||||
setCompOnlyPlayerCount(possibleCompPlayersCount);
|
||||
|
||||
|
@ -450,10 +450,10 @@ void ImageLoader::init(QPoint SpriteSize, QPoint Margins, QPoint FullSize)
|
||||
margins = Margins;
|
||||
fullSize = FullSize;
|
||||
|
||||
memset((void *)image->bits(), 0, fullSize.y() * fullSize.x());
|
||||
memset((void *)image->bits(), 0, fullSize.y() * image->bytesPerLine());
|
||||
|
||||
lineStart = image->bits();
|
||||
lineStart += margins.y() * fullSize.x() + margins.x();
|
||||
lineStart += margins.y() * image->bytesPerLine() + margins.x();
|
||||
position = lineStart;
|
||||
}
|
||||
|
||||
@ -477,7 +477,7 @@ inline void ImageLoader::Load(size_t size, ui8 color)
|
||||
|
||||
inline void ImageLoader::EndLine()
|
||||
{
|
||||
lineStart += fullSize.x();
|
||||
lineStart += image->bytesPerLine();
|
||||
position = lineStart;
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,7 @@ namespace BitmapHandler
|
||||
{
|
||||
it = 0xC;
|
||||
//auto bitmap = QBitmap::fromData(qsize, pcx + it);
|
||||
QImage image(pcx + it, width, height, QImage::Format_Indexed8);
|
||||
QImage image(pcx + it, width, height, width, QImage::Format_Indexed8);
|
||||
|
||||
//palette - last 256*3 bytes
|
||||
QVector<QRgb> colorTable;
|
||||
@ -81,7 +81,7 @@ namespace BitmapHandler
|
||||
}
|
||||
else
|
||||
{
|
||||
QImage image(pcx + it, width, height, QImage::Format_RGB32);
|
||||
QImage image(pcx + it, width, height, width * 3, QImage::Format_RGB888);
|
||||
return image;
|
||||
}
|
||||
}
|
||||
@ -117,7 +117,7 @@ namespace BitmapHandler
|
||||
{
|
||||
logGlobal->error("Failed to open %s as H3 PCX!", fname);
|
||||
}
|
||||
return image;
|
||||
return image.copy(); //copy must be returned here because buffer readFile.first used to build QImage will be cleaned after this line
|
||||
}
|
||||
else
|
||||
{ //loading via QImage
|
||||
|
Loading…
Reference in New Issue
Block a user