mirror of
https://github.com/vcmi/vcmi.git
synced 2025-04-19 12:02:24 +02:00
Restored ambient sounds functionality
This commit is contained in:
parent
cdcd5a29dd
commit
b57a07b10f
@ -1000,10 +1000,6 @@ static void handleEvent(SDL_Event & ev)
|
|||||||
case EUserEvent::FULLSCREEN_TOGGLED:
|
case EUserEvent::FULLSCREEN_TOGGLED:
|
||||||
fullScreenChanged();
|
fullScreenChanged();
|
||||||
break;
|
break;
|
||||||
case EUserEvent::INTERFACE_CHANGED:
|
|
||||||
if(LOCPLINT)
|
|
||||||
LOCPLINT->updateAmbientSounds(false);
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
logGlobal->error("Unknown user event. Code %d", ev.user.code);
|
logGlobal->error("Unknown user event. Code %d", ev.user.code);
|
||||||
break;
|
break;
|
||||||
|
@ -10,6 +10,7 @@ set(client_SRCS
|
|||||||
adventureMap/CList.cpp
|
adventureMap/CList.cpp
|
||||||
adventureMap/CMinimap.cpp
|
adventureMap/CMinimap.cpp
|
||||||
adventureMap/CResDataBar.cpp
|
adventureMap/CResDataBar.cpp
|
||||||
|
adventureMap/MapAudioPlayer.cpp
|
||||||
|
|
||||||
battle/BattleActionsController.cpp
|
battle/BattleActionsController.cpp
|
||||||
battle/BattleAnimationClasses.cpp
|
battle/BattleAnimationClasses.cpp
|
||||||
@ -128,6 +129,7 @@ set(client_HEADERS
|
|||||||
adventureMap/CList.h
|
adventureMap/CList.h
|
||||||
adventureMap/CMinimap.h
|
adventureMap/CMinimap.h
|
||||||
adventureMap/CResDataBar.h
|
adventureMap/CResDataBar.h
|
||||||
|
adventureMap/MapAudioPlayer.h
|
||||||
|
|
||||||
battle/BattleActionsController.h
|
battle/BattleActionsController.h
|
||||||
battle/BattleAnimationClasses.h
|
battle/BattleAnimationClasses.h
|
||||||
|
@ -75,7 +75,6 @@ CSoundHandler::CSoundHandler():
|
|||||||
listener(settings.listen["general"]["sound"]),
|
listener(settings.listen["general"]["sound"]),
|
||||||
ambientConfig(JsonNode(ResourceID("config/ambientSounds.json")))
|
ambientConfig(JsonNode(ResourceID("config/ambientSounds.json")))
|
||||||
{
|
{
|
||||||
allTilesSource = ambientConfig["allTilesSource"].Bool();
|
|
||||||
listener(std::bind(&CSoundHandler::onVolumeChange, this, _1));
|
listener(std::bind(&CSoundHandler::onVolumeChange, this, _1));
|
||||||
|
|
||||||
// Vectors for helper(s)
|
// Vectors for helper(s)
|
||||||
@ -259,11 +258,6 @@ int CSoundHandler::ambientGetRange() const
|
|||||||
return static_cast<int>(ambientConfig["range"].Integer());
|
return static_cast<int>(ambientConfig["range"].Integer());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSoundHandler::ambientCheckVisitable() const
|
|
||||||
{
|
|
||||||
return !allTilesSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CSoundHandler::ambientUpdateChannels(std::map<std::string, int> soundsArg)
|
void CSoundHandler::ambientUpdateChannels(std::map<std::string, int> soundsArg)
|
||||||
{
|
{
|
||||||
boost::mutex::scoped_lock guard(mutex);
|
boost::mutex::scoped_lock guard(mutex);
|
||||||
@ -278,7 +272,9 @@ void CSoundHandler::ambientUpdateChannels(std::map<std::string, int> soundsArg)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CCS->soundh->setChannelVolume(pair.second, ambientDistToVolume(soundsArg[pair.first]));
|
int volume = ambientDistToVolume(soundsArg[pair.first]);
|
||||||
|
CCS->soundh->setChannelVolume(pair.second, volume);
|
||||||
|
logGlobal->info("playing sound %s at %d", pair.first, volume);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(auto soundId : stoppedSounds)
|
for(auto soundId : stoppedSounds)
|
||||||
@ -289,8 +285,11 @@ void CSoundHandler::ambientUpdateChannels(std::map<std::string, int> soundsArg)
|
|||||||
if(!vstd::contains(ambientChannels, pair.first))
|
if(!vstd::contains(ambientChannels, pair.first))
|
||||||
{
|
{
|
||||||
int channel = CCS->soundh->playSound(pair.first, -1);
|
int channel = CCS->soundh->playSound(pair.first, -1);
|
||||||
CCS->soundh->setChannelVolume(channel, ambientDistToVolume(pair.second));
|
int volume = ambientDistToVolume(pair.second);
|
||||||
|
|
||||||
|
CCS->soundh->setChannelVolume(channel, volume);
|
||||||
CCS->soundh->ambientChannels.insert(std::make_pair(pair.first, channel));
|
CCS->soundh->ambientChannels.insert(std::make_pair(pair.first, channel));
|
||||||
|
logGlobal->info("playing sound %s at %d", pair.first, volume);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,6 @@ private:
|
|||||||
void ambientStopSound(std::string soundId);
|
void ambientStopSound(std::string soundId);
|
||||||
|
|
||||||
const JsonNode ambientConfig;
|
const JsonNode ambientConfig;
|
||||||
bool allTilesSource;
|
|
||||||
std::map<std::string, int> ambientChannels;
|
std::map<std::string, int> ambientChannels;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -75,7 +74,6 @@ public:
|
|||||||
void soundFinishedCallback(int channel);
|
void soundFinishedCallback(int channel);
|
||||||
|
|
||||||
int ambientGetRange() const;
|
int ambientGetRange() const;
|
||||||
bool ambientCheckVisitable() const;
|
|
||||||
void ambientUpdateChannels(std::map<std::string, int> currentSounds);
|
void ambientUpdateChannels(std::map<std::string, int> currentSounds);
|
||||||
void ambientStopAllChannels();
|
void ambientStopAllChannels();
|
||||||
|
|
||||||
|
@ -215,7 +215,6 @@ CPlayerInterface::CPlayerInterface(PlayerColor Player):
|
|||||||
curAction = nullptr;
|
curAction = nullptr;
|
||||||
playerID=Player;
|
playerID=Player;
|
||||||
human=true;
|
human=true;
|
||||||
currentSelection = nullptr;
|
|
||||||
battleInt = nullptr;
|
battleInt = nullptr;
|
||||||
castleInt = nullptr;
|
castleInt = nullptr;
|
||||||
makingTurn = false;
|
makingTurn = false;
|
||||||
@ -233,9 +232,6 @@ CPlayerInterface::CPlayerInterface(PlayerColor Player):
|
|||||||
|
|
||||||
CPlayerInterface::~CPlayerInterface()
|
CPlayerInterface::~CPlayerInterface()
|
||||||
{
|
{
|
||||||
if(CCS && CCS->soundh)
|
|
||||||
CCS->soundh->ambientStopAllChannels();
|
|
||||||
|
|
||||||
logGlobal->trace("\tHuman player interface for player %s being destructed", playerID.getStr());
|
logGlobal->trace("\tHuman player interface for player %s being destructed", playerID.getStr());
|
||||||
delete showingDialog;
|
delete showingDialog;
|
||||||
delete cingconsole;
|
delete cingconsole;
|
||||||
@ -341,10 +337,6 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details, bool verbose)
|
|||||||
|
|
||||||
if(makingTurn && hero->tempOwner == playerID) //we are moving our hero - we may need to update assigned path
|
if(makingTurn && hero->tempOwner == playerID) //we are moving our hero - we may need to update assigned path
|
||||||
{
|
{
|
||||||
updateAmbientSounds(false);
|
|
||||||
//We may need to change music - select new track, music handler will change it if needed
|
|
||||||
CCS->musich->playMusicFromSet("terrain", LOCPLINT->cb->getTile(hero->visitablePos())->terType->getJsonKey(), true, false);
|
|
||||||
|
|
||||||
if(details.result == TryMoveHero::TELEPORTATION)
|
if(details.result == TryMoveHero::TELEPORTATION)
|
||||||
{
|
{
|
||||||
if(paths.hasPath(hero))
|
if(paths.hasPath(hero))
|
||||||
@ -1542,17 +1534,6 @@ void CPlayerInterface::playerBlocked(int reason, bool start)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const CArmedInstance * CPlayerInterface::getSelection()
|
|
||||||
{
|
|
||||||
return currentSelection;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CPlayerInterface::setSelection(const CArmedInstance * obj)
|
|
||||||
{
|
|
||||||
currentSelection = obj;
|
|
||||||
updateAmbientSounds(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CPlayerInterface::update()
|
void CPlayerInterface::update()
|
||||||
{
|
{
|
||||||
// Make sure that gamestate won't change when GUI objects may obtain its parts on event processing or drawing request
|
// Make sure that gamestate won't change when GUI objects may obtain its parts on event processing or drawing request
|
||||||
@ -1877,7 +1858,6 @@ void CPlayerInterface::showShipyardDialogOrProblemPopup(const IShipyard *obj)
|
|||||||
|
|
||||||
void CPlayerInterface::requestReturningToMainMenu(bool won)
|
void CPlayerInterface::requestReturningToMainMenu(bool won)
|
||||||
{
|
{
|
||||||
CCS->soundh->ambientStopAllChannels();
|
|
||||||
if(won && cb->getStartInfo()->campState)
|
if(won && cb->getStartInfo()->campState)
|
||||||
CSH->startCampaignScenario(cb->getStartInfo()->campState);
|
CSH->startCampaignScenario(cb->getStartInfo()->campState);
|
||||||
else
|
else
|
||||||
@ -2226,41 +2206,3 @@ void CPlayerInterface::showWorldViewEx(const std::vector<ObjectPosInfo>& objectP
|
|||||||
EVENT_HANDLER_CALLED_BY_CLIENT;
|
EVENT_HANDLER_CALLED_BY_CLIENT;
|
||||||
adventureInt->openWorldView(objectPositions, showTerrain );
|
adventureInt->openWorldView(objectPositions, showTerrain );
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPlayerInterface::updateAmbientSounds(bool resetAll)
|
|
||||||
{
|
|
||||||
if(castleInt || battleInt || !makingTurn || !currentSelection)
|
|
||||||
{
|
|
||||||
CCS->soundh->ambientStopAllChannels();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if(!dynamic_cast<CAdvMapInt *>(GH.topInt().get()))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(resetAll)
|
|
||||||
CCS->soundh->ambientStopAllChannels();
|
|
||||||
|
|
||||||
std::map<std::string, int> currentSounds;
|
|
||||||
auto updateSounds = [&](std::string soundId, int distance) -> void
|
|
||||||
{
|
|
||||||
if(vstd::contains(currentSounds, soundId))
|
|
||||||
currentSounds[soundId] = std::max(currentSounds[soundId], distance);
|
|
||||||
else
|
|
||||||
currentSounds.insert(std::make_pair(soundId, distance));
|
|
||||||
};
|
|
||||||
|
|
||||||
int3 pos = currentSelection->getSightCenter();
|
|
||||||
std::unordered_set<int3, ShashInt3> tiles;
|
|
||||||
cb->getVisibleTilesInRange(tiles, pos, CCS->soundh->ambientGetRange(), int3::DIST_CHEBYSHEV);
|
|
||||||
for(int3 tile : tiles)
|
|
||||||
{
|
|
||||||
int dist = pos.dist(tile, int3::DIST_CHEBYSHEV);
|
|
||||||
// We want sound for every special terrain on tile and not just one on top
|
|
||||||
|
|
||||||
for(auto & soundName : CGI->mh->getAmbientSounds(tile))
|
|
||||||
updateSounds(soundName, dist);
|
|
||||||
|
|
||||||
}
|
|
||||||
CCS->soundh->ambientUpdateChannels(currentSounds);
|
|
||||||
}
|
|
||||||
|
@ -92,8 +92,6 @@ public:
|
|||||||
/// Central class for managing user interface logic
|
/// Central class for managing user interface logic
|
||||||
class CPlayerInterface : public CGameInterface, public IUpdateable
|
class CPlayerInterface : public CGameInterface, public IUpdateable
|
||||||
{
|
{
|
||||||
const CArmedInstance * currentSelection;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
HeroPathStorage paths;
|
HeroPathStorage paths;
|
||||||
|
|
||||||
@ -263,9 +261,6 @@ public:
|
|||||||
void requestReturningToMainMenu(bool won);
|
void requestReturningToMainMenu(bool won);
|
||||||
void proposeLoadingGame();
|
void proposeLoadingGame();
|
||||||
|
|
||||||
// Ambient sounds
|
|
||||||
void updateAmbientSounds(bool resetAll);
|
|
||||||
|
|
||||||
///returns true if all events are processed internally
|
///returns true if all events are processed internally
|
||||||
bool capturedAllEvents();
|
bool capturedAllEvents();
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "CResDataBar.h"
|
#include "CResDataBar.h"
|
||||||
#include "CList.h"
|
#include "CList.h"
|
||||||
#include "CInfoBar.h"
|
#include "CInfoBar.h"
|
||||||
|
#include "MapAudioPlayer.h"
|
||||||
|
|
||||||
#include "../mapView/mapHandler.h"
|
#include "../mapView/mapHandler.h"
|
||||||
#include "../mapView/MapView.h"
|
#include "../mapView/MapView.h"
|
||||||
@ -87,6 +88,7 @@ CAdvMapInt::CAdvMapInt():
|
|||||||
townList(new CTownList(ADVOPT.tlistSize, Point(ADVOPT.tlistX, ADVOPT.tlistY), ADVOPT.tlistAU, ADVOPT.tlistAD)),
|
townList(new CTownList(ADVOPT.tlistSize, Point(ADVOPT.tlistX, ADVOPT.tlistY), ADVOPT.tlistAU, ADVOPT.tlistAD)),
|
||||||
infoBar(new CInfoBar(Rect(ADVOPT.infoboxX, ADVOPT.infoboxY, 192, 192))),
|
infoBar(new CInfoBar(Rect(ADVOPT.infoboxX, ADVOPT.infoboxY, 192, 192))),
|
||||||
resdatabar(new CResDataBar),
|
resdatabar(new CResDataBar),
|
||||||
|
mapAudio(new MapAudioPlayer()),
|
||||||
terrain(new MapView(Point(ADVOPT.advmapX, ADVOPT.advmapY), Point(ADVOPT.advmapW, ADVOPT.advmapH))),
|
terrain(new MapView(Point(ADVOPT.advmapX, ADVOPT.advmapY), Point(ADVOPT.advmapW, ADVOPT.advmapH))),
|
||||||
state(NA),
|
state(NA),
|
||||||
spellBeingCasted(nullptr),
|
spellBeingCasted(nullptr),
|
||||||
@ -298,6 +300,16 @@ void CAdvMapInt::onMapViewMoved(const Rect & visibleArea, int mapLevel)
|
|||||||
minimap->onMapViewMoved(visibleArea, mapLevel);
|
minimap->onMapViewMoved(visibleArea, mapLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CAdvMapInt::onAudioResumed()
|
||||||
|
{
|
||||||
|
mapAudio->onAudioResumed();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAdvMapInt::onAudioPaused()
|
||||||
|
{
|
||||||
|
mapAudio->onAudioPaused();
|
||||||
|
}
|
||||||
|
|
||||||
void CAdvMapInt::fshowQuestlog()
|
void CAdvMapInt::fshowQuestlog()
|
||||||
{
|
{
|
||||||
LOCPLINT->showQuestLog();
|
LOCPLINT->showQuestLog();
|
||||||
@ -854,15 +866,8 @@ boost::optional<Point> CAdvMapInt::keyToMoveDirection(const SDL_Keycode & key)
|
|||||||
void CAdvMapInt::select(const CArmedInstance *sel, bool centerView)
|
void CAdvMapInt::select(const CArmedInstance *sel, bool centerView)
|
||||||
{
|
{
|
||||||
assert(sel);
|
assert(sel);
|
||||||
LOCPLINT->setSelection(sel);
|
|
||||||
selection = sel;
|
selection = sel;
|
||||||
if (LOCPLINT->battleInt == nullptr && LOCPLINT->makingTurn)
|
mapAudio->onSelectionChanged(sel);
|
||||||
{
|
|
||||||
auto pos = sel->visitablePos();
|
|
||||||
auto tile = LOCPLINT->cb->getTile(pos);
|
|
||||||
if(tile)
|
|
||||||
CCS->musich->playMusicFromSet("terrain", tile->terType->getJsonKey(), true, false);
|
|
||||||
}
|
|
||||||
if(centerView)
|
if(centerView)
|
||||||
centerOnObject(sel);
|
centerOnObject(sel);
|
||||||
|
|
||||||
@ -974,6 +979,7 @@ void CAdvMapInt::initializeNewTurn()
|
|||||||
{
|
{
|
||||||
heroList->update();
|
heroList->update();
|
||||||
townList->update();
|
townList->update();
|
||||||
|
mapAudio->onPlayerTurnStarted();
|
||||||
|
|
||||||
const CGHeroInstance * heroToSelect = nullptr;
|
const CGHeroInstance * heroToSelect = nullptr;
|
||||||
|
|
||||||
@ -1021,7 +1027,7 @@ void CAdvMapInt::endingTurn()
|
|||||||
|
|
||||||
LOCPLINT->makingTurn = false;
|
LOCPLINT->makingTurn = false;
|
||||||
LOCPLINT->cb->endTurn();
|
LOCPLINT->cb->endTurn();
|
||||||
CCS->soundh->ambientStopAllChannels();
|
mapAudio->onPlayerTurnEnded();
|
||||||
}
|
}
|
||||||
|
|
||||||
const CGObjectInstance* CAdvMapInt::getActiveObject(const int3 &mapPos)
|
const CGObjectInstance* CAdvMapInt::getActiveObject(const int3 &mapPos)
|
||||||
@ -1388,7 +1394,7 @@ void CAdvMapInt::aiTurnStarted()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
adjustActiveness(true);
|
adjustActiveness(true);
|
||||||
CCS->musich->playMusicFromSet("enemy-turn", true, false);
|
mapAudio->onEnemyTurnStarted();
|
||||||
adventureInt->minimap->setAIRadar(true);
|
adventureInt->minimap->setAIRadar(true);
|
||||||
adventureInt->infoBar->startEnemyTurn(LOCPLINT->cb->getCurrentPlayer());
|
adventureInt->infoBar->startEnemyTurn(LOCPLINT->cb->getCurrentPlayer());
|
||||||
adventureInt->infoBar->showAll(screen);//force refresh on inactive object
|
adventureInt->infoBar->showAll(screen);//force refresh on inactive object
|
||||||
|
@ -39,6 +39,7 @@ class CHeroList;
|
|||||||
class CTownList;
|
class CTownList;
|
||||||
class CInfoBar;
|
class CInfoBar;
|
||||||
class CMinimap;
|
class CMinimap;
|
||||||
|
class MapAudioPlayer;
|
||||||
|
|
||||||
struct MapDrawingInfo;
|
struct MapDrawingInfo;
|
||||||
|
|
||||||
@ -107,6 +108,8 @@ private:
|
|||||||
|
|
||||||
std::shared_ptr<CAnimation> worldViewIcons;// images for world view overlay
|
std::shared_ptr<CAnimation> worldViewIcons;// images for world view overlay
|
||||||
|
|
||||||
|
std::shared_ptr<MapAudioPlayer> mapAudio;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//functions bound to buttons
|
//functions bound to buttons
|
||||||
void fshowOverview();
|
void fshowOverview();
|
||||||
@ -163,6 +166,12 @@ public:
|
|||||||
/// visibleArea describen now visible map section measured in tiles
|
/// visibleArea describen now visible map section measured in tiles
|
||||||
void onMapViewMoved(const Rect & visibleArea, int mapLevel);
|
void onMapViewMoved(const Rect & visibleArea, int mapLevel);
|
||||||
|
|
||||||
|
/// Called when map audio should be paused, e.g. on combat or town scren access
|
||||||
|
void onAudioPaused();
|
||||||
|
|
||||||
|
/// Called when map audio should be resume, opposite to onPaused
|
||||||
|
void onAudioResumed();
|
||||||
|
|
||||||
void select(const CArmedInstance *sel, bool centerView = true);
|
void select(const CArmedInstance *sel, bool centerView = true);
|
||||||
void centerOnTile(int3 on);
|
void centerOnTile(int3 on);
|
||||||
void centerOnObject(const CGObjectInstance *obj);
|
void centerOnObject(const CGObjectInstance *obj);
|
||||||
|
@ -11,12 +11,13 @@
|
|||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
#include "CInGameConsole.h"
|
#include "CInGameConsole.h"
|
||||||
|
|
||||||
#include "../render/Colors.h"
|
|
||||||
#include "../CGameInfo.h"
|
#include "../CGameInfo.h"
|
||||||
#include "../CMusicHandler.h"
|
#include "../CMusicHandler.h"
|
||||||
#include "../CPlayerInterface.h"
|
#include "../CPlayerInterface.h"
|
||||||
#include "../gui/CGuiHandler.h"
|
|
||||||
#include "../ClientCommandManager.h"
|
#include "../ClientCommandManager.h"
|
||||||
|
#include "../adventureMap/CAdvMapInt.h"
|
||||||
|
#include "../gui/CGuiHandler.h"
|
||||||
|
#include "../render/Colors.h"
|
||||||
|
|
||||||
#include "../../CCallback.h"
|
#include "../../CCallback.h"
|
||||||
#include "../../lib/CConfigHandler.h"
|
#include "../../lib/CConfigHandler.h"
|
||||||
@ -234,7 +235,7 @@ void CInGameConsole::endEnteringText(bool processEnteredText)
|
|||||||
clientCommandThread.detach();
|
clientCommandThread.detach();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LOCPLINT->cb->sendMessage(txt, LOCPLINT->getSelection());
|
LOCPLINT->cb->sendMessage(txt, adventureInt->curArmy());
|
||||||
}
|
}
|
||||||
enteredText.clear();
|
enteredText.clear();
|
||||||
|
|
||||||
|
247
client/adventureMap/MapAudioPlayer.cpp
Normal file
247
client/adventureMap/MapAudioPlayer.cpp
Normal file
@ -0,0 +1,247 @@
|
|||||||
|
/*
|
||||||
|
* 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 "../mapView/mapHandler.h"
|
||||||
|
#include "../CPlayerInterface.h"
|
||||||
|
#include "../CGameInfo.h"
|
||||||
|
#include "../CCallback.h"
|
||||||
|
#include "../CMusicHandler.h"
|
||||||
|
|
||||||
|
#include "../../lib/mapping/CMap.h"
|
||||||
|
#include "../../lib/mapObjects/CArmedInstance.h"
|
||||||
|
#include "../../lib/mapObjects/CGHeroInstance.h"
|
||||||
|
#include "../../lib/TerrainHandler.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)
|
||||||
|
{
|
||||||
|
addObject(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapAudioPlayer::onObjectFadeOut(const CGObjectInstance * obj)
|
||||||
|
{
|
||||||
|
removeObject(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapAudioPlayer::onObjectInstantAdd(const CGObjectInstance * obj)
|
||||||
|
{
|
||||||
|
addObject(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapAudioPlayer::onObjectInstantRemove(const CGObjectInstance * obj)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
int3 currTile(obj->pos.x - fx, obj->pos.y - fy, obj->pos.z);
|
||||||
|
|
||||||
|
if(LOCPLINT->cb->isInTheMap(currTile) && obj->coveringAt(currTile.x, currTile.y))
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
int3 currTile = obj->pos + tile;
|
||||||
|
|
||||||
|
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<std::string> MapAudioPlayer::getAmbientSounds(const int3 & tile)
|
||||||
|
{
|
||||||
|
std::vector<std::string> result;
|
||||||
|
|
||||||
|
for(auto & objectID : objects[tile.z][tile.x][tile.y])
|
||||||
|
{
|
||||||
|
const auto & object = CGI->mh->getMap()->objects[objectID.getNum()];
|
||||||
|
|
||||||
|
if(object->getAmbientSound())
|
||||||
|
result.push_back(object->getAmbientSound().get());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(CGI->mh->getMap()->isCoastalTile(tile))
|
||||||
|
result.emplace_back("LOOPOCEA");
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapAudioPlayer::updateAmbientSounds()
|
||||||
|
{
|
||||||
|
std::map<std::string, int> currentSounds;
|
||||||
|
auto updateSounds = [&](std::string 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, ShashInt3> 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)
|
||||||
|
{
|
||||||
|
const auto * terrain = LOCPLINT->cb->getTile(currentSelection->visitablePos())->terType;
|
||||||
|
CCS->musich->playMusicFromSet("terrain", terrain->getJsonKey(), true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
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);
|
||||||
|
}
|
71
client/adventureMap/MapAudioPlayer.h
Normal file
71
client/adventureMap/MapAudioPlayer.h
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* MapAudioPlayer.h, 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
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../mapView/IMapRendererObserver.h"
|
||||||
|
|
||||||
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
class ObjectInstanceID;
|
||||||
|
class CArmedInstance;
|
||||||
|
VCMI_LIB_NAMESPACE_END
|
||||||
|
|
||||||
|
class MapAudioPlayer : public IMapObjectObserver
|
||||||
|
{
|
||||||
|
using MapObjectsList = std::vector<ObjectInstanceID>;
|
||||||
|
|
||||||
|
boost::multi_array<MapObjectsList, 3> objects;
|
||||||
|
const CArmedInstance * currentSelection = nullptr;
|
||||||
|
bool playerMakingTurn = false;
|
||||||
|
bool enemyMakingTurn = false;
|
||||||
|
bool audioPlaying = true;
|
||||||
|
|
||||||
|
void addObject(const CGObjectInstance * obj);
|
||||||
|
void removeObject(const CGObjectInstance * obj);
|
||||||
|
|
||||||
|
std::vector<std::string> getAmbientSounds(const int3 & tile);
|
||||||
|
void updateAmbientSounds();
|
||||||
|
void updateMusic();
|
||||||
|
void update();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// IMapObjectObserver impl
|
||||||
|
bool hasOngoingAnimations() override;
|
||||||
|
void onObjectFadeIn(const CGObjectInstance * obj) override;
|
||||||
|
void onObjectFadeOut(const CGObjectInstance * obj) override;
|
||||||
|
void onObjectInstantAdd(const CGObjectInstance * obj) override;
|
||||||
|
void onObjectInstantRemove(const CGObjectInstance * obj) override;
|
||||||
|
|
||||||
|
void onHeroMoved(const CGHeroInstance * obj, const int3 & from, const int3 & dest) override;
|
||||||
|
void onAfterHeroTeleported(const CGHeroInstance * obj, const int3 & from, const int3 & dest) override;
|
||||||
|
void onAfterHeroEmbark(const CGHeroInstance * obj, const int3 & from, const int3 & dest) override;
|
||||||
|
void onAfterHeroDisembark(const CGHeroInstance * obj, const int3 & from, const int3 & dest) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MapAudioPlayer();
|
||||||
|
~MapAudioPlayer();
|
||||||
|
|
||||||
|
/// Called whenever current adventure map selection changes
|
||||||
|
void onSelectionChanged(const CArmedInstance * newSelection);
|
||||||
|
|
||||||
|
/// Called when local player starts his turn
|
||||||
|
void onPlayerTurnStarted();
|
||||||
|
|
||||||
|
/// Called when AI or non-local player start his turn
|
||||||
|
void onEnemyTurnStarted();
|
||||||
|
|
||||||
|
/// Called when local player ends his turn
|
||||||
|
void onPlayerTurnEnded();
|
||||||
|
|
||||||
|
/// Called when map audio should be paused, e.g. on combat or town scren access
|
||||||
|
void onAudioPaused();
|
||||||
|
|
||||||
|
/// Called when map audio should be resume, opposite to onPaused
|
||||||
|
void onAudioResumed();
|
||||||
|
};
|
@ -95,7 +95,7 @@ BattleInterface::BattleInterface(const CCreatureSet *army1, const CCreatureSet *
|
|||||||
effectsController.reset(new BattleEffectsController(*this));
|
effectsController.reset(new BattleEffectsController(*this));
|
||||||
obstacleController.reset(new BattleObstacleController(*this));
|
obstacleController.reset(new BattleObstacleController(*this));
|
||||||
|
|
||||||
CCS->musich->stopMusic();
|
adventureInt->onAudioPaused();
|
||||||
setAnimationCondition(EAnimationEvents::OPENING, true);
|
setAnimationCondition(EAnimationEvents::OPENING, true);
|
||||||
|
|
||||||
GH.pushInt(windowObject);
|
GH.pushInt(windowObject);
|
||||||
@ -144,12 +144,8 @@ BattleInterface::~BattleInterface()
|
|||||||
CPlayerInterface::battleInt = nullptr;
|
CPlayerInterface::battleInt = nullptr;
|
||||||
givenCommand.cond.notify_all(); //that two lines should make any stacksController->getActiveStack() waiting thread to finish
|
givenCommand.cond.notify_all(); //that two lines should make any stacksController->getActiveStack() waiting thread to finish
|
||||||
|
|
||||||
if (adventureInt && adventureInt->curArmy())
|
if (adventureInt)
|
||||||
{
|
adventureInt->onAudioResumed();
|
||||||
//FIXME: this should be moved to adventureInt which should restore correct track based on selection/active player
|
|
||||||
const auto * terrain = LOCPLINT->cb->getTile(adventureInt->curArmy()->visitablePos())->terType;
|
|
||||||
CCS->musich->playMusicFromSet("terrain", terrain->getJsonKey(), true, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// may happen if user decided to close game while in battle
|
// may happen if user decided to close game while in battle
|
||||||
if (getAnimationCondition(EAnimationEvents::ACTION) == true)
|
if (getAnimationCondition(EAnimationEvents::ACTION) == true)
|
||||||
|
@ -126,8 +126,6 @@ void CGuiHandler::popInt(std::shared_ptr<IShowActivatable> top)
|
|||||||
if(!listInt.empty())
|
if(!listInt.empty())
|
||||||
listInt.front()->activate();
|
listInt.front()->activate();
|
||||||
totalRedraw();
|
totalRedraw();
|
||||||
|
|
||||||
pushUserEvent(EUserEvent::INTERFACE_CHANGED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGuiHandler::pushInt(std::shared_ptr<IShowActivatable> newInt)
|
void CGuiHandler::pushInt(std::shared_ptr<IShowActivatable> newInt)
|
||||||
@ -145,8 +143,6 @@ void CGuiHandler::pushInt(std::shared_ptr<IShowActivatable> newInt)
|
|||||||
newInt->activate();
|
newInt->activate();
|
||||||
objsToBlit.push_back(newInt);
|
objsToBlit.push_back(newInt);
|
||||||
totalRedraw();
|
totalRedraw();
|
||||||
|
|
||||||
pushUserEvent(EUserEvent::INTERFACE_CHANGED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGuiHandler::popInts(int howMany)
|
void CGuiHandler::popInts(int howMany)
|
||||||
@ -168,8 +164,6 @@ void CGuiHandler::popInts(int howMany)
|
|||||||
totalRedraw();
|
totalRedraw();
|
||||||
}
|
}
|
||||||
fakeMouseMove();
|
fakeMouseMove();
|
||||||
|
|
||||||
pushUserEvent(EUserEvent::INTERFACE_CHANGED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<IShowActivatable> CGuiHandler::topInt()
|
std::shared_ptr<IShowActivatable> CGuiHandler::topInt()
|
||||||
|
@ -42,7 +42,6 @@ enum class EUserEvent
|
|||||||
FULLSCREEN_TOGGLED,
|
FULLSCREEN_TOGGLED,
|
||||||
CAMPAIGN_START_SCENARIO,
|
CAMPAIGN_START_SCENARIO,
|
||||||
FORCE_QUIT, //quit client without question
|
FORCE_QUIT, //quit client without question
|
||||||
INTERFACE_CHANGED
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// A fps manager which holds game updates at a constant rate
|
// A fps manager which holds game updates at a constant rate
|
||||||
|
@ -136,21 +136,6 @@ bool CMapHandler::isInMap( const int3 & tile)
|
|||||||
return map->isInTheMap(tile);
|
return map->isInTheMap(tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> CMapHandler::getAmbientSounds(const int3 & tile)
|
|
||||||
{
|
|
||||||
std::vector<std::string> result;
|
|
||||||
|
|
||||||
//for(auto & ttObj : ttiles[tile.z][tile.x][tile.y].objects)
|
|
||||||
//{
|
|
||||||
// if(ttObj.ambientSound)
|
|
||||||
// result.push_back(ttObj.ambientSound.get());
|
|
||||||
//}
|
|
||||||
if(map->isCoastalTile(tile))
|
|
||||||
result.emplace_back("LOOPOCEA");
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CMapHandler::onObjectFadeIn(const CGObjectInstance * obj)
|
void CMapHandler::onObjectFadeIn(const CGObjectInstance * obj)
|
||||||
{
|
{
|
||||||
for (auto * observer : observers)
|
for (auto * observer : observers)
|
||||||
|
@ -28,17 +28,10 @@ VCMI_LIB_NAMESPACE_BEGIN
|
|||||||
|
|
||||||
class CGObjectInstance;
|
class CGObjectInstance;
|
||||||
class CGHeroInstance;
|
class CGHeroInstance;
|
||||||
class CGBoat;
|
|
||||||
class CMap;
|
class CMap;
|
||||||
struct TerrainTile;
|
|
||||||
class PlayerColor;
|
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_END
|
VCMI_LIB_NAMESPACE_END
|
||||||
|
|
||||||
struct SDL_Surface;
|
|
||||||
class CAnimation;
|
|
||||||
class IImage;
|
|
||||||
class CMapHandler;
|
|
||||||
class IMapObjectObserver;
|
class IMapObjectObserver;
|
||||||
|
|
||||||
class CMapHandler
|
class CMapHandler
|
||||||
@ -74,9 +67,6 @@ public:
|
|||||||
/// returns string description for terrain interaction
|
/// returns string description for terrain interaction
|
||||||
std::string getTerrainDescr(const int3 & pos, bool rightClick) const;
|
std::string getTerrainDescr(const int3 & pos, bool rightClick) const;
|
||||||
|
|
||||||
/// returns list of ambient sounds for specified tile
|
|
||||||
std::vector<std::string> getAmbientSounds(const int3 & tile);
|
|
||||||
|
|
||||||
/// determines if the map is ready to handle new hero movement (not available during fading animations)
|
/// determines if the map is ready to handle new hero movement (not available during fading animations)
|
||||||
bool hasOngoingAnimations();
|
bool hasOngoingAnimations();
|
||||||
|
|
||||||
|
@ -1188,11 +1188,13 @@ CCastleInterface::CCastleInterface(const CGTownInstance * Town, const CGTownInst
|
|||||||
townlist->onSelect = std::bind(&CCastleInterface::townChange, this);
|
townlist->onSelect = std::bind(&CCastleInterface::townChange, this);
|
||||||
|
|
||||||
recreateIcons();
|
recreateIcons();
|
||||||
|
adventureInt->onAudioPaused();
|
||||||
CCS->musich->playMusic(town->town->clientInfo.musicTheme, true, false);
|
CCS->musich->playMusic(town->town->clientInfo.musicTheme, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
CCastleInterface::~CCastleInterface()
|
CCastleInterface::~CCastleInterface()
|
||||||
{
|
{
|
||||||
|
adventureInt->onAudioResumed();
|
||||||
if(LOCPLINT->castleInt == this)
|
if(LOCPLINT->castleInt == this)
|
||||||
LOCPLINT->castleInt = nullptr;
|
LOCPLINT->castleInt = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,4 @@
|
|||||||
{
|
{
|
||||||
// By default visitable objects only have ambient sound source on visitable tile
|
|
||||||
// Static objects and special terrains that have ambient sound have source on all tiles
|
|
||||||
// If set to true then all tiles will become source for visitable objects
|
|
||||||
"allTilesSource": false,
|
|
||||||
// By default SDL2_Mixer allocate 8 channels, but more sounds require more channels
|
// By default SDL2_Mixer allocate 8 channels, but more sounds require more channels
|
||||||
"allocateChannels" : 16,
|
"allocateChannels" : 16,
|
||||||
// Maximal ambient sounds volume must be about 20% of global effects volume
|
// Maximal ambient sounds volume must be about 20% of global effects volume
|
||||||
|
Loading…
x
Reference in New Issue
Block a user