mirror of
https://github.com/vcmi/vcmi.git
synced 2025-01-12 02:28:11 +02:00
Merge remote-tracking branch 'refs/remotes/vcmi/develop' into battleint_refactor
This commit is contained in:
commit
3e58d1e3c5
@ -237,7 +237,7 @@ bool isObjectPassable(const Nullkiller * ai, const CGObjectInstance * obj)
|
||||
|
||||
bool isObjectPassable(const CGObjectInstance * obj)
|
||||
{
|
||||
return isObjectPassable(obj, ai->playerID, cb->getPlayerRelations(obj->tempOwner, ai->playerID));
|
||||
return isObjectPassable(obj, ai->playerID, ai->myCb->getPlayerRelations(obj->tempOwner, ai->playerID));
|
||||
}
|
||||
|
||||
// Pathfinder internal helper
|
||||
@ -344,11 +344,14 @@ uint64_t timeElapsed(std::chrono::time_point<std::chrono::high_resolution_clock>
|
||||
// todo: move to obj manager
|
||||
bool shouldVisit(const Nullkiller * ai, const CGHeroInstance * h, const CGObjectInstance * obj)
|
||||
{
|
||||
auto relations = ai->cb->getPlayerRelations(obj->tempOwner, h->tempOwner);
|
||||
|
||||
switch(obj->ID)
|
||||
{
|
||||
case Obj::TOWN:
|
||||
case Obj::HERO: //never visit our heroes at random
|
||||
return obj->tempOwner != h->tempOwner; //do not visit our towns at random
|
||||
return relations == PlayerRelations::ENEMIES; //do not visit our towns at random
|
||||
|
||||
case Obj::BORDER_GATE:
|
||||
{
|
||||
for(auto q : ai->cb->getMyQuests())
|
||||
@ -378,9 +381,12 @@ bool shouldVisit(const Nullkiller * ai, const CGHeroInstance * h, const CGObject
|
||||
}
|
||||
case Obj::CREATURE_GENERATOR1:
|
||||
{
|
||||
if(obj->tempOwner != h->tempOwner)
|
||||
if(relations == PlayerRelations::ENEMIES)
|
||||
return true; //flag just in case
|
||||
|
||||
if(relations == PlayerRelations::ALLIES)
|
||||
return false;
|
||||
|
||||
const CGDwelling * d = dynamic_cast<const CGDwelling *>(obj);
|
||||
|
||||
for(auto level : d->creatures)
|
||||
@ -420,7 +426,7 @@ bool shouldVisit(const Nullkiller * ai, const CGHeroInstance * h, const CGObject
|
||||
break;
|
||||
}
|
||||
case Obj::LIBRARY_OF_ENLIGHTENMENT:
|
||||
if(h->level < 12)
|
||||
if(h->level < 10)
|
||||
return false;
|
||||
break;
|
||||
case Obj::TREE_OF_KNOWLEDGE:
|
||||
|
@ -1387,6 +1387,8 @@ static void handleEvent(SDL_Event & ev)
|
||||
{
|
||||
if(ourCampaign->mapsRemaining.size())
|
||||
{
|
||||
GH.pushInt(CMM);
|
||||
GH.pushInt(CMM->menu);
|
||||
CMM->openCampaignLobby(ourCampaign);
|
||||
}
|
||||
};
|
||||
|
@ -34,17 +34,6 @@ static std::string sounds[] = {
|
||||
#undef VCMI_SOUND_NAME
|
||||
#undef VCMI_SOUND_FILE
|
||||
|
||||
// Not pretty, but there's only one music handler object in the game.
|
||||
static void soundFinishedCallbackC(int channel)
|
||||
{
|
||||
CCS->soundh->soundFinishedCallback(channel);
|
||||
}
|
||||
|
||||
static void musicFinishedCallbackC()
|
||||
{
|
||||
CCS->musich->musicFinishedCallback();
|
||||
}
|
||||
|
||||
void CAudioBase::init()
|
||||
{
|
||||
if (initialized)
|
||||
@ -140,8 +129,10 @@ void CSoundHandler::init()
|
||||
|
||||
if (initialized)
|
||||
{
|
||||
// Load sounds
|
||||
Mix_ChannelFinished(soundFinishedCallbackC);
|
||||
Mix_ChannelFinished([](int channel)
|
||||
{
|
||||
CCS->soundh->soundFinishedCallback(channel);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -244,7 +235,7 @@ int CSoundHandler::playSoundFromSet(std::vector<soundBase::soundID> &sound_vec)
|
||||
return playSound(*RandomGeneratorUtil::nextItem(sound_vec, CRandomGenerator::getDefault()));
|
||||
}
|
||||
|
||||
void CSoundHandler::stopSound( int handler )
|
||||
void CSoundHandler::stopSound(int handler)
|
||||
{
|
||||
if (initialized && handler != -1)
|
||||
Mix_HaltChannel(handler);
|
||||
@ -368,24 +359,24 @@ CMusicHandler::CMusicHandler():
|
||||
for(const ResourceID & file : mp3files)
|
||||
{
|
||||
if(boost::algorithm::istarts_with(file.getName(), "MUSIC/Combat"))
|
||||
addEntryToSet("battle", file.getName(), file.getName());
|
||||
addEntryToSet("battle", file.getName());
|
||||
else if(boost::algorithm::istarts_with(file.getName(), "MUSIC/AITheme"))
|
||||
addEntryToSet("enemy-turn", file.getName(), file.getName());
|
||||
addEntryToSet("enemy-turn", file.getName());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CMusicHandler::loadTerrainSounds()
|
||||
void CMusicHandler::loadTerrainMusicThemes()
|
||||
{
|
||||
for (const auto & terrain : CGI->terrainTypeHandler->terrains())
|
||||
{
|
||||
addEntryToSet("terrain", terrain.name, "Music/" + terrain.musicFilename);
|
||||
addEntryToSet("terrain_" + terrain.name, "Music/" + terrain.musicFilename);
|
||||
}
|
||||
}
|
||||
|
||||
void CMusicHandler::addEntryToSet(const std::string & set, const std::string & musicID, const std::string & musicURI)
|
||||
void CMusicHandler::addEntryToSet(const std::string & set, const std::string & musicURI)
|
||||
{
|
||||
musicsSet[set][musicID] = musicURI;
|
||||
musicsSet[set].push_back(musicURI);
|
||||
}
|
||||
|
||||
void CMusicHandler::init()
|
||||
@ -393,7 +384,12 @@ void CMusicHandler::init()
|
||||
CAudioBase::init();
|
||||
|
||||
if (initialized)
|
||||
Mix_HookMusicFinished(musicFinishedCallbackC);
|
||||
{
|
||||
Mix_HookMusicFinished([]()
|
||||
{
|
||||
CCS->musich->musicFinishedCallback();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void CMusicHandler::release()
|
||||
@ -413,12 +409,17 @@ void CMusicHandler::release()
|
||||
|
||||
void CMusicHandler::playMusic(const std::string & musicURI, bool loop, bool fromStart)
|
||||
{
|
||||
if (current && current->isTrack(musicURI))
|
||||
if (current && current->isPlaying() && current->isTrack(musicURI))
|
||||
return;
|
||||
|
||||
queueNext(this, "", musicURI, loop, fromStart);
|
||||
}
|
||||
|
||||
void CMusicHandler::playMusicFromSet(const std::string & musicSet, const std::string & entryID, bool loop, bool fromStart)
|
||||
{
|
||||
playMusicFromSet(musicSet + "_" + entryID, loop, fromStart);
|
||||
}
|
||||
|
||||
void CMusicHandler::playMusicFromSet(const std::string & whichSet, bool loop, bool fromStart)
|
||||
{
|
||||
auto selectedSet = musicsSet.find(whichSet);
|
||||
@ -428,36 +429,13 @@ void CMusicHandler::playMusicFromSet(const std::string & whichSet, bool loop, bo
|
||||
return;
|
||||
}
|
||||
|
||||
if (current && current->isSet(whichSet))
|
||||
if (current && current->isPlaying() && current->isSet(whichSet))
|
||||
return;
|
||||
|
||||
// in this mode - play random track from set
|
||||
queueNext(this, whichSet, "", loop, fromStart);
|
||||
}
|
||||
|
||||
void CMusicHandler::playMusicFromSet(const std::string & whichSet, const std::string & entryID, bool loop, bool fromStart)
|
||||
{
|
||||
auto selectedSet = musicsSet.find(whichSet);
|
||||
if (selectedSet == musicsSet.end())
|
||||
{
|
||||
logGlobal->error("Error: playing music from non-existing set: %s", whichSet);
|
||||
return;
|
||||
}
|
||||
|
||||
auto selectedEntry = selectedSet->second.find(entryID);
|
||||
if (selectedEntry == selectedSet->second.end())
|
||||
{
|
||||
logGlobal->error("Error: playing non-existing entry %s from set: %s", entryID, whichSet);
|
||||
return;
|
||||
}
|
||||
|
||||
if (current && current->isTrack(selectedEntry->second))
|
||||
return;
|
||||
|
||||
// in this mode - play specific track from set
|
||||
queueNext(this, "", selectedEntry->second, loop, fromStart);
|
||||
}
|
||||
|
||||
void CMusicHandler::queueNext(std::unique_ptr<MusicEntry> queued)
|
||||
{
|
||||
if (!initialized)
|
||||
@ -513,7 +491,7 @@ void CMusicHandler::musicFinishedCallback()
|
||||
|
||||
if (current.get() != nullptr)
|
||||
{
|
||||
//return if current music still not finished
|
||||
// if music is looped, play it again
|
||||
if (current->play())
|
||||
return;
|
||||
else
|
||||
@ -530,6 +508,7 @@ void CMusicHandler::musicFinishedCallback()
|
||||
MusicEntry::MusicEntry(CMusicHandler *owner, std::string setName, std::string musicURI, bool looped, bool fromStart):
|
||||
owner(owner),
|
||||
music(nullptr),
|
||||
playing(false),
|
||||
startTime(uint32_t(-1)),
|
||||
startPosition(0),
|
||||
loop(looped ? -1 : 1),
|
||||
@ -578,29 +557,41 @@ bool MusicEntry::play()
|
||||
if (!setName.empty())
|
||||
{
|
||||
const auto & set = owner->musicsSet[setName];
|
||||
load(RandomGeneratorUtil::nextItem(set, CRandomGenerator::getDefault())->second);
|
||||
const auto & iter = RandomGeneratorUtil::nextItem(set, CRandomGenerator::getDefault());
|
||||
load(*iter);
|
||||
}
|
||||
|
||||
logGlobal->trace("Playing music file %s", currentName);
|
||||
|
||||
if ( !fromStart && owner->trackPositions.count(currentName) > 0 && owner->trackPositions[currentName] > 0)
|
||||
if (!fromStart && owner->trackPositions.count(currentName) > 0 && owner->trackPositions[currentName] > 0)
|
||||
{
|
||||
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());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(Mix_PlayMusic(music, 1) == -1)
|
||||
else
|
||||
{
|
||||
logGlobal->error("Unable to play music (%s)", Mix_GetError());
|
||||
return false;
|
||||
startPosition = 0;
|
||||
|
||||
if(Mix_PlayMusic(music, 1) == -1)
|
||||
{
|
||||
logGlobal->error("Unable to play music (%s)", Mix_GetError());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
startTime = SDL_GetTicks();
|
||||
playing = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -608,6 +599,7 @@ bool MusicEntry::stop(int fade_ms)
|
||||
{
|
||||
if (Mix_PlayingMusic())
|
||||
{
|
||||
playing = false;
|
||||
loop = 0;
|
||||
uint32_t endTime = SDL_GetTicks();
|
||||
assert(startTime != uint32_t(-1));
|
||||
@ -621,6 +613,11 @@ bool MusicEntry::stop(int fade_ms)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MusicEntry::isPlaying()
|
||||
{
|
||||
return playing;
|
||||
}
|
||||
|
||||
bool MusicEntry::isSet(std::string set)
|
||||
{
|
||||
return !setName.empty() && set == setName;
|
||||
|
@ -100,22 +100,23 @@ class MusicEntry
|
||||
|
||||
int loop; // -1 = indefinite
|
||||
bool fromStart;
|
||||
bool playing;
|
||||
uint32_t startTime;
|
||||
uint32_t startPosition;
|
||||
//if not null - set from which music will be randomly selected
|
||||
std::string setName;
|
||||
std::string currentName;
|
||||
|
||||
|
||||
void load(std::string musicURI);
|
||||
|
||||
public:
|
||||
bool isSet(std::string setName);
|
||||
bool isTrack(std::string trackName);
|
||||
|
||||
MusicEntry(CMusicHandler *owner, std::string setName, std::string musicURI, bool looped, bool fromStart);
|
||||
~MusicEntry();
|
||||
|
||||
bool isSet(std::string setName);
|
||||
bool isTrack(std::string trackName);
|
||||
bool isPlaying();
|
||||
|
||||
bool play();
|
||||
bool stop(int fade_ms=0);
|
||||
};
|
||||
@ -123,7 +124,6 @@ public:
|
||||
class CMusicHandler: public CAudioBase
|
||||
{
|
||||
private:
|
||||
|
||||
//update volume on configuration change
|
||||
SettingsListener listener;
|
||||
void onVolumeChange(const JsonNode &volumeNode);
|
||||
@ -133,18 +133,21 @@ private:
|
||||
|
||||
void queueNext(CMusicHandler *owner, const std::string & setName, const std::string & musicURI, bool looped, bool fromStart);
|
||||
void queueNext(std::unique_ptr<MusicEntry> queued);
|
||||
void musicFinishedCallback();
|
||||
|
||||
std::map<std::string, std::map<std::string, std::string>> musicsSet;
|
||||
/// map <set name> -> <list of URI's to tracks belonging to the said set>
|
||||
std::map<std::string, std::vector<std::string>> musicsSet;
|
||||
/// stored position, in seconds at which music player should resume playing this track
|
||||
std::map<std::string, float> trackPositions;
|
||||
|
||||
public:
|
||||
|
||||
CMusicHandler();
|
||||
|
||||
/// add entry with URI musicURI in set. Track will have ID musicID
|
||||
void addEntryToSet(const std::string & set, const std::string & entryID, const std::string & musicURI);
|
||||
void addEntryToSet(const std::string & set, const std::string & musicURI);
|
||||
|
||||
void init() override;
|
||||
void loadTerrainSounds();
|
||||
void loadTerrainMusicThemes();
|
||||
void release() override;
|
||||
void setVolume(ui32 percent) override;
|
||||
|
||||
@ -152,10 +155,10 @@ public:
|
||||
void playMusic(const std::string & musicURI, bool loop, bool fromStart);
|
||||
/// play random track from this set
|
||||
void playMusicFromSet(const std::string & musicSet, bool loop, bool fromStart);
|
||||
/// play specific track from set
|
||||
/// play random track from set (musicSet, entryID)
|
||||
void playMusicFromSet(const std::string & musicSet, const std::string & entryID, bool loop, bool fromStart);
|
||||
/// stops currently playing music by fading out it over fade_ms and starts next scheduled track, if any
|
||||
void stopMusic(int fade_ms=1000);
|
||||
void musicFinishedCallback();
|
||||
|
||||
friend class MusicEntry;
|
||||
};
|
||||
|
@ -154,7 +154,7 @@ void CPlayerInterface::init(std::shared_ptr<Environment> ENV, std::shared_ptr<CC
|
||||
env = ENV;
|
||||
|
||||
CCS->soundh->loadHorseSounds();
|
||||
CCS->musich->loadTerrainSounds();
|
||||
CCS->musich->loadTerrainMusicThemes();
|
||||
|
||||
initializeHeroTownList();
|
||||
|
||||
@ -220,27 +220,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;
|
||||
@ -1718,432 +1697,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 )
|
||||
|
@ -432,6 +432,11 @@ void CBonusSelection::startMap()
|
||||
exitCb();
|
||||
}
|
||||
};
|
||||
|
||||
//block buttons immediately
|
||||
buttonStart->block(true);
|
||||
buttonRestart->block(true);
|
||||
buttonBack->block(true);
|
||||
|
||||
if(LOCPLINT) // we're currently ingame, so ask for starting new map and end game
|
||||
{
|
||||
|
@ -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();
|
||||
|
@ -206,12 +206,13 @@ void CHeroArtPlace::clickLeft(tribool down, bool previousState)
|
||||
bool CHeroArtPlace::askToAssemble(const CArtifactInstance *art, ArtifactPosition slot,
|
||||
const CGHeroInstance *hero)
|
||||
{
|
||||
assert(art != nullptr);
|
||||
assert(hero != nullptr);
|
||||
std::vector<const CArtifact *> assemblyPossibilities = art->assemblyPossibilities(hero);
|
||||
assert(art);
|
||||
assert(hero);
|
||||
bool assembleEqipped = !ArtifactUtils::isSlotBackpack(slot);
|
||||
auto assemblyPossibilities = art->assemblyPossibilities(hero, assembleEqipped);
|
||||
|
||||
// If the artifact can be assembled, display dialog.
|
||||
for(const CArtifact *combination : assemblyPossibilities)
|
||||
for(const auto * combination : assemblyPossibilities)
|
||||
{
|
||||
LOCPLINT->showArtifactAssemblyDialog(
|
||||
art->artType,
|
||||
@ -229,27 +230,22 @@ void CHeroArtPlace::clickRight(tribool down, bool previousState)
|
||||
{
|
||||
if(ourArt && down && !locked && text.size() && !picked) //if there is no description or it's a lock, do nothing ;]
|
||||
{
|
||||
if(slotID < GameConstants::BACKPACK_START)
|
||||
if(ourOwner->allowedAssembling)
|
||||
{
|
||||
if(ourOwner->allowedAssembling)
|
||||
// If the artifact can be assembled, display dialog.
|
||||
if(askToAssemble(ourArt, slotID, ourOwner->curHero))
|
||||
{
|
||||
std::vector<const CArtifact *> assemblyPossibilities = ourArt->assemblyPossibilities(ourOwner->curHero);
|
||||
return;
|
||||
}
|
||||
|
||||
// If the artifact can be assembled, display dialog.
|
||||
if(askToAssemble(ourArt, slotID, ourOwner->curHero))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise if the artifact can be diasassembled, display dialog.
|
||||
if(ourArt->canBeDisassembled())
|
||||
{
|
||||
LOCPLINT->showArtifactAssemblyDialog(
|
||||
ourArt->artType,
|
||||
nullptr,
|
||||
std::bind(&CCallback::assembleArtifacts, LOCPLINT->cb.get(), ourOwner->curHero, slotID, false, ArtifactID()));
|
||||
return;
|
||||
}
|
||||
// Otherwise if the artifact can be diasassembled, display dialog.
|
||||
if(ourArt->canBeDisassembled())
|
||||
{
|
||||
LOCPLINT->showArtifactAssemblyDialog(
|
||||
ourArt->artType,
|
||||
nullptr,
|
||||
std::bind(&CCallback::assembleArtifacts, LOCPLINT->cb.get(), ourOwner->curHero, slotID, false, ArtifactID()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -819,16 +815,15 @@ CArtifactsOfHero::ArtPlacePtr CArtifactsOfHero::getArtPlace(int slot)
|
||||
}
|
||||
}
|
||||
|
||||
void CArtifactsOfHero::artifactAssembled(const ArtifactLocation &al)
|
||||
void CArtifactsOfHero::artifactUpdateSlots(const ArtifactLocation & al)
|
||||
{
|
||||
if(al.isHolder(curHero))
|
||||
updateWornSlots();
|
||||
}
|
||||
|
||||
void CArtifactsOfHero::artifactDisassembled(const ArtifactLocation &al)
|
||||
{
|
||||
if(al.isHolder(curHero))
|
||||
updateWornSlots();
|
||||
{
|
||||
if(ArtifactUtils::isSlotBackpack(al.slot))
|
||||
updateBackpackSlots();
|
||||
else
|
||||
updateWornSlots();
|
||||
}
|
||||
}
|
||||
|
||||
void CArtifactsOfHero::updateWornSlots(bool redrawParent)
|
||||
@ -840,6 +835,16 @@ void CArtifactsOfHero::updateWornSlots(bool redrawParent)
|
||||
updateParentWindow();
|
||||
}
|
||||
|
||||
void CArtifactsOfHero::updateBackpackSlots(bool redrawParent)
|
||||
{
|
||||
for(auto artPlace : backpack)
|
||||
updateSlot(artPlace->slotID);
|
||||
scrollBackpack(0);
|
||||
|
||||
if(redrawParent)
|
||||
updateParentWindow();
|
||||
}
|
||||
|
||||
const CGHeroInstance * CArtifactsOfHero::getHero() const
|
||||
{
|
||||
return curHero;
|
||||
@ -910,7 +915,7 @@ void CWindowWithArtifacts::artifactDisassembled(const ArtifactLocation &artLoc)
|
||||
{
|
||||
std::shared_ptr<CArtifactsOfHero> realPtr = artSetWeak.lock();
|
||||
if(realPtr)
|
||||
realPtr->artifactDisassembled(artLoc);
|
||||
realPtr->artifactUpdateSlots(artLoc);
|
||||
}
|
||||
}
|
||||
|
||||
@ -920,7 +925,7 @@ void CWindowWithArtifacts::artifactAssembled(const ArtifactLocation &artLoc)
|
||||
{
|
||||
std::shared_ptr<CArtifactsOfHero> realPtr = artSetWeak.lock();
|
||||
if(realPtr)
|
||||
realPtr->artifactAssembled(artLoc);
|
||||
realPtr->artifactUpdateSlots(artLoc);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -140,8 +140,7 @@ public:
|
||||
void realizeCurrentTransaction(); //calls callback with parameters stored in commonInfo
|
||||
void artifactMoved(const ArtifactLocation &src, const ArtifactLocation &dst);
|
||||
void artifactRemoved(const ArtifactLocation &al);
|
||||
void artifactAssembled(const ArtifactLocation &al);
|
||||
void artifactDisassembled(const ArtifactLocation &al);
|
||||
void artifactUpdateSlots(const ArtifactLocation &al);
|
||||
ArtPlacePtr getArtPlace(int slot);//may return null
|
||||
|
||||
void setHero(const CGHeroInstance * hero);
|
||||
@ -153,7 +152,8 @@ public:
|
||||
void markPossibleSlots(const CArtifactInstance* art);
|
||||
void unmarkSlots(bool withRedraw = true); //unmarks slots in all visible AOHs
|
||||
void unmarkLocalSlots(bool withRedraw = true); //unmarks slots in that particular AOH
|
||||
void updateWornSlots (bool redrawParent = true);
|
||||
void updateWornSlots(bool redrawParent = true);
|
||||
void updateBackpackSlots(bool redrawParent = true);
|
||||
|
||||
void updateSlot(ArtifactPosition i);
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
"WEEKLY_GROWTH_PERCENT" : 10,
|
||||
"NEUTRAL_STACK_EXP_DAILY" : 500,
|
||||
"MAX_BUILDING_PER_TURN" : 1,
|
||||
"DWELLINGS_ACCUMULATE_CREATURES" : true,
|
||||
"DWELLINGS_ACCUMULATE_CREATURES" : false,
|
||||
"ALL_CREATURES_GET_DOUBLE_MONTHS" : false,
|
||||
"NEGATIVE_LUCK" : false,
|
||||
"MAX_HEROES_AVAILABLE_PER_PLAYER" : 16,
|
||||
|
@ -27,7 +27,7 @@
|
||||
"base" : {
|
||||
"base" : {
|
||||
"visitableFrom" : [ "+++", "+-+", "+++" ],
|
||||
"mask" : [ "VV", "AV"]
|
||||
"mask" : [ "VVV", "VAV"]
|
||||
},
|
||||
"sounds" : {
|
||||
"removal" : ["KILLFADE"]
|
||||
|
@ -160,8 +160,6 @@ bool CModManager::canUninstallMod(QString modname)
|
||||
if(!mod.isInstalled())
|
||||
return addError(modname, "Mod is not installed");
|
||||
|
||||
if(mod.isEnabled())
|
||||
return addError(modname, "Mod must be disabled first");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -870,26 +870,36 @@ bool CArtifactInstance::canBeDisassembled() const
|
||||
return bool(artType->constituents);
|
||||
}
|
||||
|
||||
std::vector<const CArtifact *> CArtifactInstance::assemblyPossibilities(const CArtifactSet *h) const
|
||||
std::vector<const CArtifact *> CArtifactInstance::assemblyPossibilities(const CArtifactSet * h, bool equipped) const
|
||||
{
|
||||
std::vector<const CArtifact *> ret;
|
||||
if(artType->constituents) //combined artifact already: no combining of combined artifacts... for now.
|
||||
return ret;
|
||||
|
||||
for(const CArtifact * artifact : artType->constituentOf)
|
||||
for(const auto * artifact : artType->constituentOf)
|
||||
{
|
||||
assert(artifact->constituents);
|
||||
bool possible = true;
|
||||
|
||||
for(const CArtifact * constituent : *artifact->constituents) //check if all constituents are available
|
||||
for(const auto * constituent : *artifact->constituents) //check if all constituents are available
|
||||
{
|
||||
const bool noBackpack = false;
|
||||
const bool notAlreadyAssembled = false;
|
||||
|
||||
if(!h->hasArt(constituent->id, true, noBackpack, notAlreadyAssembled)) //constituent must be equipped
|
||||
if(equipped)
|
||||
{
|
||||
possible = false;
|
||||
break;
|
||||
// Search for equipped arts
|
||||
if (!h->hasArt(constituent->id, true, false, false))
|
||||
{
|
||||
possible = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Search in backpack
|
||||
if(!h->hasArtBackpack(constituent->id))
|
||||
{
|
||||
possible = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1195,22 +1205,41 @@ ArtifactPosition CArtifactSet::getArtPos(int aid, bool onlyWorn, bool allowLocke
|
||||
return result.empty() ? ArtifactPosition{ArtifactPosition::PRE_FIRST} : result[0];
|
||||
}
|
||||
|
||||
ArtifactPosition CArtifactSet::getArtBackpackPos(int aid) const
|
||||
{
|
||||
const auto result = getBackpackArtPositions(aid);
|
||||
return result.empty() ? ArtifactPosition{ArtifactPosition::PRE_FIRST} : result[0];
|
||||
}
|
||||
|
||||
std::vector<ArtifactPosition> CArtifactSet::getAllArtPositions(int aid, bool onlyWorn, bool allowLocked, bool getAll) const
|
||||
{
|
||||
std::vector<ArtifactPosition> result;
|
||||
for(auto i = artifactsWorn.cbegin(); i != artifactsWorn.cend(); i++)
|
||||
if(i->second.artifact->artType->id == aid && (allowLocked || !i->second.locked))
|
||||
result.push_back(i->first);
|
||||
for(auto & slotInfo : artifactsWorn)
|
||||
if(slotInfo.second.artifact->artType->id == aid && (allowLocked || !slotInfo.second.locked))
|
||||
result.push_back(slotInfo.first);
|
||||
|
||||
if(onlyWorn)
|
||||
return result;
|
||||
if(!getAll && !result.empty())
|
||||
return result;
|
||||
|
||||
for(int i = 0; i < artifactsInBackpack.size(); i++)
|
||||
if(artifactsInBackpack[i].artifact->artType->id == aid)
|
||||
result.push_back(ArtifactPosition(GameConstants::BACKPACK_START + i));
|
||||
auto backpackPositions = getBackpackArtPositions(aid);
|
||||
result.insert(result.end(), backpackPositions.begin(), backpackPositions.end());
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<ArtifactPosition> CArtifactSet::getBackpackArtPositions(int aid) const
|
||||
{
|
||||
std::vector<ArtifactPosition> result;
|
||||
|
||||
si32 backpackPosition = GameConstants::BACKPACK_START;
|
||||
for(auto & artInfo : artifactsInBackpack)
|
||||
{
|
||||
auto * art = artInfo.getArt();
|
||||
if(art && art->artType->id == aid)
|
||||
result.emplace_back(backpackPosition);
|
||||
backpackPosition++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1249,6 +1278,11 @@ bool CArtifactSet::hasArt(
|
||||
return getArtPosCount(aid, onlyWorn, searchBackpackAssemblies, allowLocked) > 0;
|
||||
}
|
||||
|
||||
bool CArtifactSet::hasArtBackpack(ui32 aid) const
|
||||
{
|
||||
return getBackpackArtPositions(aid).size() > 0;
|
||||
}
|
||||
|
||||
unsigned CArtifactSet::getArtPosCount(int aid, bool onlyWorn, bool searchBackpackAssemblies, bool allowLocked) const
|
||||
{
|
||||
const auto allPositions = getAllArtPositions(aid, onlyWorn, allowLocked, true);
|
||||
@ -1536,4 +1570,9 @@ DLL_LINKAGE bool ArtifactUtils::checkSpellbookIsNeeded(const CGHeroInstance * he
|
||||
return false;
|
||||
}
|
||||
|
||||
DLL_LINKAGE bool ArtifactUtils::isSlotBackpack(ArtifactPosition slot)
|
||||
{
|
||||
return slot >= GameConstants::BACKPACK_START;
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -163,7 +163,7 @@ public:
|
||||
/// of itself, additionally truth is returned for constituents of combined arts
|
||||
virtual bool isPart(const CArtifactInstance *supposedPart) const;
|
||||
|
||||
std::vector<const CArtifact *> assemblyPossibilities(const CArtifactSet *h) const;
|
||||
std::vector<const CArtifact *> assemblyPossibilities(const CArtifactSet * h, bool equipped) const;
|
||||
void move(ArtifactLocation src, ArtifactLocation dst);
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
@ -329,13 +329,16 @@ public:
|
||||
/// (if more than one such artifact lower ID is returned)
|
||||
ArtifactPosition getArtPos(int aid, bool onlyWorn = true, bool allowLocked = true) const;
|
||||
ArtifactPosition getArtPos(const CArtifactInstance *art) const;
|
||||
ArtifactPosition getArtBackpackPos(int aid) const;
|
||||
std::vector<ArtifactPosition> getAllArtPositions(int aid, bool onlyWorn, bool allowLocked, bool getAll) const;
|
||||
std::vector<ArtifactPosition> getBackpackArtPositions(int aid) const;
|
||||
const CArtifactInstance *getArtByInstanceId(ArtifactInstanceID artInstId) const;
|
||||
/// Search for constituents of assemblies in backpack which do not have an ArtifactPosition
|
||||
const CArtifactInstance *getHiddenArt(int aid) const;
|
||||
const CCombinedArtifactInstance *getAssemblyByConstituent(int aid) const;
|
||||
/// Checks if hero possess artifact of given id (either in backack or worn)
|
||||
bool hasArt(ui32 aid, bool onlyWorn = false, bool searchBackpackAssemblies = false, bool allowLocked = true) const;
|
||||
bool hasArtBackpack(ui32 aid) const;
|
||||
bool isPositionFree(ArtifactPosition pos, bool onlyLockCheck = false) const;
|
||||
unsigned getArtPosCount(int aid, bool onlyWorn = true, bool searchBackpackAssemblies = true, bool allowLocked = true) const;
|
||||
|
||||
@ -386,6 +389,7 @@ namespace ArtifactUtils
|
||||
DLL_LINKAGE std::vector<ArtifactPosition> unmovablePositions(); // TODO: Make this constexpr when the toolset is upgraded
|
||||
DLL_LINKAGE bool isArtRemovable(const std::pair<ArtifactPosition, ArtSlotInfo> & slot);
|
||||
DLL_LINKAGE bool checkSpellbookIsNeeded(const CGHeroInstance * heroPtr, ArtifactID artID, ArtifactPosition slot);
|
||||
DLL_LINKAGE bool isSlotBackpack(ArtifactPosition slot);
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -2857,6 +2857,8 @@ void CGameState::replaceHeroesPlaceholders(const std::vector<CGameState::Campaig
|
||||
heroToPlace->tempOwner = heroPlaceholder->tempOwner;
|
||||
heroToPlace->pos = heroPlaceholder->pos;
|
||||
heroToPlace->type = VLC->heroh->objects[heroToPlace->subID];
|
||||
heroToPlace->appearance = VLC->objtypeh->getHandlerFor(Obj::HERO,
|
||||
heroToPlace->type->heroClass->getIndex())->getTemplates().front();
|
||||
|
||||
for(auto &&i : heroToPlace->stacks)
|
||||
i.second->type = VLC->creh->objects[i.second->getCreatureID()];
|
||||
|
@ -1089,7 +1089,7 @@ DLL_LINKAGE void EraseArtifact::applyGs(CGameState *gs)
|
||||
DLL_LINKAGE void MoveArtifact::applyGs(CGameState * gs)
|
||||
{
|
||||
CArtifactInstance * art = src.getArt();
|
||||
if(dst.slot < GameConstants::BACKPACK_START)
|
||||
if(!ArtifactUtils::isSlotBackpack(dst.slot))
|
||||
assert(!dst.getArt());
|
||||
|
||||
art->move(src, dst);
|
||||
@ -1114,7 +1114,7 @@ DLL_LINKAGE void BulkMoveArtifacts::applyGs(CGameState * gs)
|
||||
// so all the following indices will be affected. Thus, we need to update
|
||||
// the subsequent artifact slots to account for that
|
||||
auto srcPos = slot.srcPos;
|
||||
if((srcPos >= GameConstants::BACKPACK_START) && (operation != EBulkArtsOp::BULK_PUT))
|
||||
if(ArtifactUtils::isSlotBackpack(srcPos) && (operation != EBulkArtsOp::BULK_PUT))
|
||||
{
|
||||
srcPos = ArtifactPosition(srcPos.num - numBackpackArtifactsMoved);
|
||||
}
|
||||
@ -1167,26 +1167,36 @@ DLL_LINKAGE void BulkMoveArtifacts::applyGs(CGameState * gs)
|
||||
|
||||
DLL_LINKAGE void AssembledArtifact::applyGs(CGameState *gs)
|
||||
{
|
||||
CArtifactSet *artSet = al.getHolderArtSet();
|
||||
CArtifactSet * artSet = al.getHolderArtSet();
|
||||
const CArtifactInstance *transformedArt = al.getArt();
|
||||
assert(transformedArt);
|
||||
assert(vstd::contains(transformedArt->assemblyPossibilities(artSet), builtArt));
|
||||
bool combineEquipped = !ArtifactUtils::isSlotBackpack(al.slot);
|
||||
assert(vstd::contains(transformedArt->assemblyPossibilities(artSet, combineEquipped), builtArt));
|
||||
UNUSED(transformedArt);
|
||||
|
||||
auto combinedArt = new CCombinedArtifactInstance(builtArt);
|
||||
gs->map->addNewArtifactInstance(combinedArt);
|
||||
//retrieve all constituents
|
||||
// Retrieve all constituents
|
||||
for(const CArtifact * constituent : *builtArt->constituents)
|
||||
{
|
||||
ArtifactPosition pos = artSet->getArtPos(constituent->id);
|
||||
ArtifactPosition pos = combineEquipped ? artSet->getArtPos(constituent->id, true, false) :
|
||||
artSet->getArtBackpackPos(constituent->id);
|
||||
assert(pos >= 0);
|
||||
CArtifactInstance *constituentInstance = artSet->getArt(pos);
|
||||
CArtifactInstance * constituentInstance = artSet->getArt(pos);
|
||||
|
||||
//move constituent from hero to be part of new, combined artifact
|
||||
constituentInstance->removeFrom(ArtifactLocation(al.artHolder, pos));
|
||||
combinedArt->addAsConstituent(constituentInstance, pos);
|
||||
if(!vstd::contains(combinedArt->artType->possibleSlots[artSet->bearerType()], al.slot) && vstd::contains(combinedArt->artType->possibleSlots[artSet->bearerType()], pos))
|
||||
al.slot = pos;
|
||||
if(combineEquipped)
|
||||
{
|
||||
if(!vstd::contains(combinedArt->artType->possibleSlots[artSet->bearerType()], al.slot)
|
||||
&& vstd::contains(combinedArt->artType->possibleSlots[artSet->bearerType()], pos))
|
||||
al.slot = pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
al.slot = std::min(al.slot, pos);
|
||||
}
|
||||
}
|
||||
|
||||
//put new combined artifacts
|
||||
|
@ -170,6 +170,9 @@ class VCMIDirsWIN32 final : public IVCMIDirs
|
||||
|
||||
void VCMIDirsWIN32::init()
|
||||
{
|
||||
std::locale::global(boost::locale::generator().generate("en_US.UTF-8"));
|
||||
boost::filesystem::path::imbue(std::locale());
|
||||
|
||||
// Call base (init dirs)
|
||||
IVCMIDirs::init();
|
||||
|
||||
@ -698,15 +701,6 @@ namespace VCMIDirs
|
||||
static bool initialized = false;
|
||||
if (!initialized)
|
||||
{
|
||||
#ifdef VCMI_WINDOWS
|
||||
std::locale::global(boost::locale::generator().generate("en_US.UTF-8"));
|
||||
#endif
|
||||
|
||||
#ifdef VCMI_XDG
|
||||
setenv("LC_ALL", "C", 1);
|
||||
#endif
|
||||
boost::filesystem::path::imbue(std::locale());
|
||||
|
||||
singleton.init();
|
||||
initialized = true;
|
||||
}
|
||||
@ -714,5 +708,4 @@ namespace VCMIDirs
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -261,13 +261,12 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const
|
||||
auto * info = Obstacle(id).getInfo();
|
||||
return info && !info->isAbsoluteObstacle && info->isAppropriate(curB->terrainType, battlefieldType);
|
||||
};
|
||||
|
||||
RangeGenerator obidgen(0, VLC->obstacleHandler->objects.size() - 1, ourRand);
|
||||
|
||||
if(r.rand(1,100) <= 40) //put cliff-like obstacle
|
||||
{
|
||||
try
|
||||
{
|
||||
RangeGenerator obidgen(0, VLC->obstacleHandler->objects.size() - 1, ourRand);
|
||||
auto obstPtr = std::make_shared<CObstacleInstance>();
|
||||
obstPtr->obstacleType = CObstacleInstance::ABSOLUTE_OBSTACLE;
|
||||
obstPtr->ID = obidgen.getSuchNumber(appropriateAbsoluteObstacle);
|
||||
@ -289,6 +288,7 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const
|
||||
{
|
||||
while(tilesToBlock > 0)
|
||||
{
|
||||
RangeGenerator obidgen(0, VLC->obstacleHandler->objects.size() - 1, ourRand);
|
||||
auto tileAccessibility = curB->getAccesibility();
|
||||
const int obid = obidgen.getSuchNumber(appropriateUsualObstacle);
|
||||
const ObstacleInfo &obi = *Obstacle(obid).getInfo();
|
||||
|
@ -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
|
||||
|
@ -4031,13 +4031,15 @@ bool CGameHandler::assembleArtifacts (ObjectInstanceID heroID, ArtifactPosition
|
||||
if (!destArtifact)
|
||||
COMPLAIN_RET("assembleArtifacts: there is no such artifact instance!");
|
||||
|
||||
if (assemble)
|
||||
if(assemble)
|
||||
{
|
||||
CArtifact *combinedArt = VLC->arth->objects[assembleTo];
|
||||
if (!combinedArt->constituents)
|
||||
if(!combinedArt->constituents)
|
||||
COMPLAIN_RET("assembleArtifacts: Artifact being attempted to assemble is not a combined artifacts!");
|
||||
if (!vstd::contains(destArtifact->assemblyPossibilities(hero), combinedArt))
|
||||
bool combineEquipped = !ArtifactUtils::isSlotBackpack(artifactSlot);
|
||||
if(!vstd::contains(destArtifact->assemblyPossibilities(hero, combineEquipped), combinedArt))
|
||||
COMPLAIN_RET("assembleArtifacts: It's impossible to assemble requested artifact!");
|
||||
|
||||
|
||||
if(ArtifactUtils::checkSpellbookIsNeeded(hero, assembleTo, artifactSlot))
|
||||
giveHeroNewArtifact(hero, VLC->arth->objects[ArtifactID::SPELLBOOK], ArtifactPosition::SPELLBOOK);
|
||||
|
Loading…
Reference in New Issue
Block a user