2023-10-19 16:19:09 +02:00
|
|
|
/*
|
|
|
|
* MapAudioPlayer.cpp, part of VCMI engine
|
|
|
|
*
|
|
|
|
* Authors: listed in file AUTHORS in main folder
|
|
|
|
*
|
|
|
|
* License: GNU General Public License v2.0 or later
|
|
|
|
* Full text of license available in license.txt file, in main folder
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
#include "StdInc.h"
|
|
|
|
#include "MapAudioPlayer.h"
|
|
|
|
|
|
|
|
#include "../CCallback.h"
|
|
|
|
#include "../CGameInfo.h"
|
|
|
|
#include "../CPlayerInterface.h"
|
|
|
|
#include "../mapView/mapHandler.h"
|
2024-05-02 14:55:20 +02:00
|
|
|
#include "../media/IMusicPlayer.h"
|
|
|
|
#include "../media/ISoundPlayer.h"
|
2023-10-19 16:19:09 +02:00
|
|
|
|
2024-06-01 17:28:17 +02:00
|
|
|
#include "../../lib/CRandomGenerator.h"
|
2023-10-19 16:19:09 +02:00
|
|
|
#include "../../lib/TerrainHandler.h"
|
|
|
|
#include "../../lib/mapObjects/CArmedInstance.h"
|
|
|
|
#include "../../lib/mapObjects/CGHeroInstance.h"
|
|
|
|
#include "../../lib/mapping/CMap.h"
|
|
|
|
|
|
|
|
bool MapAudioPlayer::hasOngoingAnimations()
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MapAudioPlayer::onHeroMoved(const CGHeroInstance * obj, const int3 & from, const int3 & dest)
|
|
|
|
{
|
|
|
|
if(obj == currentSelection)
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MapAudioPlayer::onAfterHeroTeleported(const CGHeroInstance * obj, const int3 & from, const int3 & dest)
|
|
|
|
{
|
|
|
|
if(obj == currentSelection)
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MapAudioPlayer::onAfterHeroEmbark(const CGHeroInstance * obj, const int3 & from, const int3 & dest)
|
|
|
|
{
|
|
|
|
if(obj == currentSelection)
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MapAudioPlayer::onAfterHeroDisembark(const CGHeroInstance * obj, const int3 & from, const int3 & dest)
|
|
|
|
{
|
|
|
|
if(obj == currentSelection)
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MapAudioPlayer::onObjectFadeIn(const CGObjectInstance * obj, const PlayerColor & initiator)
|
|
|
|
{
|
|
|
|
addObject(obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
void MapAudioPlayer::onObjectFadeOut(const CGObjectInstance * obj, const PlayerColor & initiator)
|
|
|
|
{
|
|
|
|
removeObject(obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
void MapAudioPlayer::onObjectInstantAdd(const CGObjectInstance * obj, const PlayerColor & initiator)
|
|
|
|
{
|
|
|
|
addObject(obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
void MapAudioPlayer::onObjectInstantRemove(const CGObjectInstance * obj, const PlayerColor & initiator)
|
|
|
|
{
|
|
|
|
removeObject(obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
void MapAudioPlayer::addObject(const CGObjectInstance * obj)
|
|
|
|
{
|
|
|
|
if(obj->isTile2Terrain())
|
|
|
|
{
|
|
|
|
// terrain overlay - all covering tiles act as sound source
|
|
|
|
for(int fx = 0; fx < obj->getWidth(); ++fx)
|
|
|
|
{
|
|
|
|
for(int fy = 0; fy < obj->getHeight(); ++fy)
|
|
|
|
{
|
2024-10-02 18:40:06 +02:00
|
|
|
int3 currTile(obj->anchorPos().x - fx, obj->anchorPos().y - fy, obj->anchorPos().z);
|
2023-10-19 16:19:09 +02:00
|
|
|
|
2024-10-02 18:40:06 +02:00
|
|
|
if(LOCPLINT->cb->isInTheMap(currTile) && obj->coveringAt(currTile))
|
2023-10-19 16:19:09 +02:00
|
|
|
objects[currTile.z][currTile.x][currTile.y].push_back(obj->id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(obj->isVisitable())
|
|
|
|
{
|
|
|
|
// visitable object - visitable tile acts as sound source
|
|
|
|
int3 currTile = obj->visitablePos();
|
|
|
|
|
|
|
|
if(LOCPLINT->cb->isInTheMap(currTile))
|
|
|
|
objects[currTile.z][currTile.x][currTile.y].push_back(obj->id);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!obj->isVisitable())
|
|
|
|
{
|
|
|
|
// static object - blocking tiles act as sound source
|
|
|
|
auto tiles = obj->getBlockedOffsets();
|
|
|
|
|
|
|
|
for(const auto & tile : tiles)
|
|
|
|
{
|
2024-10-02 18:40:06 +02:00
|
|
|
int3 currTile = obj->anchorPos() + tile;
|
2023-10-19 16:19:09 +02:00
|
|
|
|
|
|
|
if(LOCPLINT->cb->isInTheMap(currTile))
|
|
|
|
objects[currTile.z][currTile.x][currTile.y].push_back(obj->id);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void MapAudioPlayer::removeObject(const CGObjectInstance * obj)
|
|
|
|
{
|
|
|
|
for(int z = 0; z < LOCPLINT->cb->getMapSize().z; z++)
|
|
|
|
for(int x = 0; x < LOCPLINT->cb->getMapSize().x; x++)
|
|
|
|
for(int y = 0; y < LOCPLINT->cb->getMapSize().y; y++)
|
|
|
|
vstd::erase(objects[z][x][y], obj->id);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<AudioPath> MapAudioPlayer::getAmbientSounds(const int3 & tile)
|
|
|
|
{
|
|
|
|
std::vector<AudioPath> result;
|
|
|
|
|
|
|
|
for(auto & objectID : objects[tile.z][tile.x][tile.y])
|
|
|
|
{
|
|
|
|
const auto & object = CGI->mh->getMap()->objects[objectID.getNum()];
|
|
|
|
|
|
|
|
assert(object);
|
|
|
|
if (!object)
|
|
|
|
logGlobal->warn("Already removed object %d found on tile! (%d %d %d)", objectID.getNum(), tile.x, tile.y, tile.z);
|
|
|
|
|
2024-06-01 17:28:17 +02:00
|
|
|
if(object)
|
|
|
|
{
|
|
|
|
auto ambientSound = object->getAmbientSound(CRandomGenerator::getDefault());
|
|
|
|
if (ambientSound)
|
|
|
|
result.push_back(ambientSound.value());
|
|
|
|
}
|
2023-10-19 16:19:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if(CGI->mh->getMap()->isCoastalTile(tile))
|
|
|
|
result.emplace_back(AudioPath::builtin("LOOPOCEA"));
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MapAudioPlayer::updateAmbientSounds()
|
|
|
|
{
|
|
|
|
std::map<AudioPath, int> currentSounds;
|
|
|
|
auto updateSounds = [&](const AudioPath& soundId, int distance) -> void
|
|
|
|
{
|
|
|
|
if(vstd::contains(currentSounds, soundId))
|
|
|
|
currentSounds[soundId] = std::min(currentSounds[soundId], distance);
|
|
|
|
else
|
|
|
|
currentSounds.insert(std::make_pair(soundId, distance));
|
|
|
|
};
|
|
|
|
|
|
|
|
int3 pos = currentSelection->getSightCenter();
|
|
|
|
std::unordered_set<int3> tiles;
|
|
|
|
LOCPLINT->cb->getVisibleTilesInRange(tiles, pos, CCS->soundh->ambientGetRange(), int3::DIST_CHEBYSHEV);
|
|
|
|
for(int3 tile : tiles)
|
|
|
|
{
|
|
|
|
int dist = pos.dist(tile, int3::DIST_CHEBYSHEV);
|
|
|
|
|
|
|
|
for(auto & soundName : getAmbientSounds(tile))
|
|
|
|
updateSounds(soundName, dist);
|
|
|
|
}
|
|
|
|
CCS->soundh->ambientUpdateChannels(currentSounds);
|
|
|
|
}
|
|
|
|
|
|
|
|
void MapAudioPlayer::updateMusic()
|
|
|
|
{
|
|
|
|
if(audioPlaying && playerMakingTurn && currentSelection)
|
|
|
|
{
|
2024-01-04 23:54:06 +02:00
|
|
|
const auto * tile = LOCPLINT->cb->getTile(currentSelection->visitablePos());
|
|
|
|
|
|
|
|
if (tile)
|
|
|
|
CCS->musich->playMusicFromSet("terrain", tile->terType->getJsonKey(), true, false);
|
2023-10-19 16:19:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if(audioPlaying && enemyMakingTurn)
|
|
|
|
{
|
|
|
|
CCS->musich->playMusicFromSet("enemy-turn", true, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void MapAudioPlayer::update()
|
|
|
|
{
|
|
|
|
updateMusic();
|
|
|
|
|
|
|
|
if(audioPlaying && playerMakingTurn && currentSelection)
|
|
|
|
updateAmbientSounds();
|
|
|
|
}
|
|
|
|
|
|
|
|
MapAudioPlayer::MapAudioPlayer()
|
|
|
|
{
|
|
|
|
auto mapSize = LOCPLINT->cb->getMapSize();
|
|
|
|
|
|
|
|
objects.resize(boost::extents[mapSize.z][mapSize.x][mapSize.y]);
|
|
|
|
|
|
|
|
for(const auto & obj : CGI->mh->getMap()->objects)
|
|
|
|
{
|
|
|
|
if (obj)
|
|
|
|
addObject(obj);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MapAudioPlayer::~MapAudioPlayer()
|
|
|
|
{
|
|
|
|
CCS->soundh->ambientStopAllChannels();
|
|
|
|
CCS->musich->stopMusic(1000);
|
|
|
|
}
|
|
|
|
|
|
|
|
void MapAudioPlayer::onSelectionChanged(const CArmedInstance * newSelection)
|
|
|
|
{
|
|
|
|
currentSelection = newSelection;
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MapAudioPlayer::onAudioPaused()
|
|
|
|
{
|
|
|
|
audioPlaying = false;
|
|
|
|
CCS->soundh->ambientStopAllChannels();
|
|
|
|
CCS->musich->stopMusic(1000);
|
|
|
|
}
|
|
|
|
|
|
|
|
void MapAudioPlayer::onAudioResumed()
|
|
|
|
{
|
|
|
|
audioPlaying = true;
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MapAudioPlayer::onPlayerTurnStarted()
|
|
|
|
{
|
|
|
|
enemyMakingTurn = false;
|
|
|
|
playerMakingTurn = true;
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MapAudioPlayer::onEnemyTurnStarted()
|
|
|
|
{
|
|
|
|
playerMakingTurn = false;
|
|
|
|
enemyMakingTurn = true;
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MapAudioPlayer::onPlayerTurnEnded()
|
|
|
|
{
|
|
|
|
playerMakingTurn = false;
|
|
|
|
enemyMakingTurn = false;
|
|
|
|
CCS->soundh->ambientStopAllChannels();
|
|
|
|
CCS->musich->stopMusic(1000);
|
|
|
|
}
|