1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-12 02:28:11 +02:00

Use ResourcePath for audio files

This commit is contained in:
Ivan Savenko 2023-09-04 13:03:15 +03:00
parent 97b7d44c88
commit 8dfdfffd87
59 changed files with 195 additions and 192 deletions

View File

@ -387,7 +387,7 @@ void AIGateway::heroCreated(const CGHeroInstance * h)
NET_EVENT_HANDLER;
}
void AIGateway::advmapSpellCast(const CGHeroInstance * caster, int spellID)
void AIGateway::advmapSpellCast(const CGHeroInstance * caster, SpellID spellID)
{
LOG_TRACE_PARAMS(logAi, "spellID '%i", spellID);
NET_EVENT_HANDLER;

View File

@ -152,7 +152,7 @@ public:
void showHillFortWindow(const CGObjectInstance * object, const CGHeroInstance * visitor) override;
void playerBonusChanged(const Bonus & bonus, bool gain) override;
void heroCreated(const CGHeroInstance *) override;
void advmapSpellCast(const CGHeroInstance * caster, int spellID) override;
void advmapSpellCast(const CGHeroInstance * caster, SpellID spellID) override;
void showInfoDialog(EInfoWindowMode type, const std::string & text, const std::vector<Component> & components, int soundID) override;
void requestRealized(PackageApplied * pa) override;
void receivedResource() override;

View File

@ -475,7 +475,7 @@ void VCAI::heroCreated(const CGHeroInstance * h)
NET_EVENT_HANDLER;
}
void VCAI::advmapSpellCast(const CGHeroInstance * caster, int spellID)
void VCAI::advmapSpellCast(const CGHeroInstance * caster, SpellID spellID)
{
LOG_TRACE_PARAMS(logAi, "spellID '%i", spellID);
NET_EVENT_HANDLER;

View File

@ -185,7 +185,7 @@ public:
void showHillFortWindow(const CGObjectInstance * object, const CGHeroInstance * visitor) override;
void playerBonusChanged(const Bonus & bonus, bool gain) override;
void heroCreated(const CGHeroInstance *) override;
void advmapSpellCast(const CGHeroInstance * caster, int spellID) override;
void advmapSpellCast(const CGHeroInstance * caster, SpellID spellID) override;
void showInfoDialog(EInfoWindowMode type, const std::string & text, const std::vector<Component> & components, int soundID) override;
void requestRealized(PackageApplied * pa) override;
void receivedResource() override;

View File

@ -119,25 +119,25 @@ void CSoundHandler::release()
}
// Allocate an SDL chunk and cache it.
Mix_Chunk *CSoundHandler::GetSoundChunk(std::string &sound, bool cache)
Mix_Chunk *CSoundHandler::GetSoundChunk(const AudioPath & sound, bool cache)
{
try
{
if (cache && soundChunks.find(sound) != soundChunks.end())
return soundChunks[sound].first;
auto data = CResourceHandler::get()->load(ResourcePath(std::string("SOUNDS/") + sound, EResType::SOUND))->readAll();
auto data = CResourceHandler::get()->load(sound.addPrefix("SOUNDS/"))->readAll();
SDL_RWops *ops = SDL_RWFromMem(data.first.get(), (int)data.second);
Mix_Chunk *chunk = Mix_LoadWAV_RW(ops, 1); // will free ops
if (cache)
soundChunks.insert(std::pair<std::string, CachedChunk>(sound, std::make_pair (chunk, std::move (data.first))));
soundChunks.insert({sound, std::make_pair (chunk, std::move (data.first))});
return chunk;
}
catch(std::exception &e)
{
logGlobal->warn("Cannot get sound %s chunk: %s", sound, e.what());
logGlobal->warn("Cannot get sound %s chunk: %s", sound.getOriginalName(), e.what());
return nullptr;
}
}
@ -153,7 +153,7 @@ int CSoundHandler::ambientDistToVolume(int distance) const
return volume * (int)ambientConfig["volume"].Integer() / 100;
}
void CSoundHandler::ambientStopSound(std::string soundId)
void CSoundHandler::ambientStopSound(const AudioPath & soundId)
{
stopSound(ambientChannels[soundId]);
setChannelVolume(ambientChannels[soundId], volume);
@ -163,13 +163,13 @@ void CSoundHandler::ambientStopSound(std::string soundId)
int CSoundHandler::playSound(soundBase::soundID soundID, int repeats)
{
assert(soundID < soundBase::sound_after_last);
auto sound = sounds[soundID];
logGlobal->trace("Attempt to play sound %d with file name %s with cache", soundID, sound);
auto sound = AudioPath::builtin(sounds[soundID]);
logGlobal->trace("Attempt to play sound %d with file name %s with cache", soundID, sound.getOriginalName());
return playSound(sound, repeats, true);
}
int CSoundHandler::playSound(std::string sound, int repeats, bool cache)
int CSoundHandler::playSound(const AudioPath & sound, int repeats, bool cache)
{
if (!initialized || sound.empty())
return -1;
@ -182,7 +182,7 @@ int CSoundHandler::playSound(std::string sound, int repeats, bool cache)
channel = Mix_PlayChannel(-1, chunk, repeats);
if (channel == -1)
{
logGlobal->error("Unable to play sound file %s , error %s", sound, Mix_GetError());
logGlobal->error("Unable to play sound file %s , error %s", sound.getOriginalName(), Mix_GetError());
if (!cache)
Mix_FreeChunk(chunk);
}
@ -290,14 +290,14 @@ int CSoundHandler::ambientGetRange() const
return static_cast<int>(ambientConfig["range"].Integer());
}
void CSoundHandler::ambientUpdateChannels(std::map<std::string, int> soundsArg)
void CSoundHandler::ambientUpdateChannels(std::map<AudioPath, int> soundsArg)
{
boost::mutex::scoped_lock guard(mutex);
std::vector<std::string> stoppedSounds;
std::vector<AudioPath> stoppedSounds;
for(auto & pair : ambientChannels)
{
const std::string & soundId = pair.first;
const auto & soundId = pair.first;
const int channel = pair.second;
if(!vstd::contains(soundsArg, soundId))
@ -320,7 +320,7 @@ void CSoundHandler::ambientUpdateChannels(std::map<std::string, int> soundsArg)
for(auto & pair : soundsArg)
{
const std::string & soundId = pair.first;
const auto & soundId = pair.first;
const int distance = pair.second;
if(!vstd::contains(ambientChannels, soundId))
@ -372,9 +372,9 @@ CMusicHandler::CMusicHandler():
for(const ResourcePath & file : mp3files)
{
if(boost::algorithm::istarts_with(file.getName(), "MUSIC/Combat"))
addEntryToSet("battle", file.getName());
addEntryToSet("battle", AudioPath::fromResource(file));
else if(boost::algorithm::istarts_with(file.getName(), "MUSIC/AITheme"))
addEntryToSet("enemy-turn", file.getName());
addEntryToSet("enemy-turn", AudioPath::fromResource(file));
}
}
@ -383,11 +383,11 @@ void CMusicHandler::loadTerrainMusicThemes()
{
for (const auto & terrain : CGI->terrainTypeHandler->objects)
{
addEntryToSet("terrain_" + terrain->getJsonKey(), "Music/" + terrain->musicFilename);
addEntryToSet("terrain_" + terrain->getJsonKey(), terrain->musicFilename);
}
}
void CMusicHandler::addEntryToSet(const std::string & set, const std::string & musicURI)
void CMusicHandler::addEntryToSet(const std::string & set, const AudioPath & musicURI)
{
musicsSet[set].push_back(musicURI);
}
@ -421,7 +421,7 @@ void CMusicHandler::release()
CAudioBase::release();
}
void CMusicHandler::playMusic(const std::string & musicURI, bool loop, bool fromStart)
void CMusicHandler::playMusic(const AudioPath & musicURI, bool loop, bool fromStart)
{
boost::mutex::scoped_lock guard(mutex);
@ -451,7 +451,7 @@ void CMusicHandler::playMusicFromSet(const std::string & whichSet, bool loop, bo
return;
// in this mode - play random track from set
queueNext(this, whichSet, "", loop, fromStart);
queueNext(this, whichSet, AudioPath(), loop, fromStart);
}
void CMusicHandler::queueNext(std::unique_ptr<MusicEntry> queued)
@ -468,7 +468,7 @@ void CMusicHandler::queueNext(std::unique_ptr<MusicEntry> queued)
}
}
void CMusicHandler::queueNext(CMusicHandler *owner, const std::string & setName, const std::string & musicURI, bool looped, bool fromStart)
void CMusicHandler::queueNext(CMusicHandler *owner, const std::string & setName, const AudioPath & musicURI, bool looped, bool fromStart)
{
queueNext(std::make_unique<MusicEntry>(owner, setName, musicURI, looped, fromStart));
}
@ -523,7 +523,7 @@ void CMusicHandler::musicFinishedCallback()
});
}
MusicEntry::MusicEntry(CMusicHandler *owner, std::string setName, std::string musicURI, bool looped, bool fromStart):
MusicEntry::MusicEntry(CMusicHandler *owner, std::string setName, const AudioPath & musicURI, bool looped, bool fromStart):
owner(owner),
music(nullptr),
playing(false),
@ -552,16 +552,16 @@ MusicEntry::~MusicEntry()
Mix_HaltMusic();
}
logGlobal->trace("Del-ing music file %s", currentName);
logGlobal->trace("Del-ing music file %s", currentName.getOriginalName());
if (music)
Mix_FreeMusic(music);
}
void MusicEntry::load(std::string musicURI)
void MusicEntry::load(const AudioPath & musicURI)
{
if (music)
{
logGlobal->trace("Del-ing music file %s", currentName);
logGlobal->trace("Del-ing music file %s", currentName.getOriginalName());
Mix_FreeMusic(music);
music = nullptr;
}
@ -569,22 +569,22 @@ void MusicEntry::load(std::string musicURI)
currentName = musicURI;
music = nullptr;
logGlobal->trace("Loading music file %s", musicURI);
logGlobal->trace("Loading music file %s", musicURI.getOriginalName());
try
{
auto musicFile = MakeSDLRWops(CResourceHandler::get()->load(ResourcePath(std::move(musicURI), EResType::SOUND)));
auto musicFile = MakeSDLRWops(CResourceHandler::get()->load(musicURI));
music = Mix_LoadMUS_RW(musicFile, SDL_TRUE);
}
catch(std::exception &e)
{
logGlobal->error("Failed to load music. setName=%s\tmusicURI=%s", setName, musicURI);
logGlobal->error("Failed to load music. setName=%s\tmusicURI=%s", setName, musicURI.getOriginalName());
logGlobal->error("Exception: %s", e.what());
}
if(!music)
{
logGlobal->warn("Warning: Cannot open %s: %s", currentName, Mix_GetError());
logGlobal->warn("Warning: Cannot open %s: %s", currentName.getOriginalName(), Mix_GetError());
return;
}
}
@ -601,7 +601,7 @@ bool MusicEntry::play()
load(*iter);
}
logGlobal->trace("Playing music file %s", currentName);
logGlobal->trace("Playing music file %s", currentName.getOriginalName());
if (!fromStart && owner->trackPositions.count(currentName) > 0 && owner->trackPositions[currentName] > 0)
{
@ -646,7 +646,7 @@ bool MusicEntry::stop(int fade_ms)
assert(startTime != uint32_t(-1));
float playDuration = (endTime - startTime + startPosition) / 1000.f;
owner->trackPositions[currentName] = playDuration;
logGlobal->trace("Stopping music file %s at %f", currentName, playDuration);
logGlobal->trace("Stopping music file %s at %f", currentName.getOriginalName(), playDuration);
Mix_FadeOutMusic(fade_ms);
return true;
@ -664,7 +664,7 @@ bool MusicEntry::isSet(std::string set)
return !setName.empty() && set == setName;
}
bool MusicEntry::isTrack(std::string track)
bool MusicEntry::isTrack(const AudioPath & track)
{
return setName.empty() && track == currentName;
}

View File

@ -35,15 +35,14 @@ public:
class CSoundHandler: public CAudioBase
{
private:
//soundBase::soundID getSoundID(const std::string &fileName);
//update volume on configuration change
SettingsListener listener;
void onVolumeChange(const JsonNode &volumeNode);
using CachedChunk = std::pair<Mix_Chunk *, std::unique_ptr<ui8[]>>;
std::map<std::string, CachedChunk> soundChunks;
std::map<AudioPath, CachedChunk> soundChunks;
Mix_Chunk *GetSoundChunk(std::string &sound, bool cache);
Mix_Chunk *GetSoundChunk(const AudioPath & sound, bool cache);
/// have entry for every currently active channel
/// vector will be empty if callback was not set
@ -54,12 +53,12 @@ private:
boost::mutex mutexCallbacks;
int ambientDistToVolume(int distance) const;
void ambientStopSound(std::string soundId);
void ambientStopSound(const AudioPath & soundId);
void updateChannelVolume(int channel);
const JsonNode ambientConfig;
std::map<std::string, int> ambientChannels;
std::map<AudioPath, int> ambientChannels;
std::map<int, int> channelVolumes;
void initCallback(int channel, const std::function<void()> & function);
@ -76,7 +75,7 @@ public:
// Sounds
int playSound(soundBase::soundID soundID, int repeats=0);
int playSound(std::string sound, int repeats=0, bool cache=false);
int playSound(const AudioPath & sound, int repeats=0, bool cache=false);
int playSoundFromSet(std::vector<soundBase::soundID> &sound_vec);
void stopSound(int handler);
@ -84,16 +83,13 @@ public:
void soundFinishedCallback(int channel);
int ambientGetRange() const;
void ambientUpdateChannels(std::map<std::string, int> currentSounds);
void ambientUpdateChannels(std::map<AudioPath, int> currentSounds);
void ambientStopAllChannels();
// Sets
std::vector<soundBase::soundID> battleIntroSounds;
};
// Helper //now it looks somewhat useless
#define battle_sound(creature,what_sound) creature->sounds.what_sound
class CMusicHandler;
//Class for handling one music file
@ -109,16 +105,16 @@ class MusicEntry
uint32_t startPosition;
//if not null - set from which music will be randomly selected
std::string setName;
std::string currentName;
AudioPath currentName;
void load(std::string musicURI);
void load(const AudioPath & musicURI);
public:
MusicEntry(CMusicHandler *owner, std::string setName, std::string musicURI, bool looped, bool fromStart);
MusicEntry(CMusicHandler *owner, std::string setName, const AudioPath & musicURI, bool looped, bool fromStart);
~MusicEntry();
bool isSet(std::string setName);
bool isTrack(std::string trackName);
bool isTrack(const AudioPath & trackName);
bool isPlaying();
bool play();
@ -135,20 +131,20 @@ private:
std::unique_ptr<MusicEntry> current;
std::unique_ptr<MusicEntry> next;
void queueNext(CMusicHandler *owner, const std::string & setName, const std::string & musicURI, bool looped, bool fromStart);
void queueNext(CMusicHandler *owner, const std::string & setName, const AudioPath & musicURI, bool looped, bool fromStart);
void queueNext(std::unique_ptr<MusicEntry> queued);
void musicFinishedCallback();
/// map <set name> -> <list of URI's to tracks belonging to the said set>
std::map<std::string, std::vector<std::string>> musicsSet;
std::map<std::string, std::vector<AudioPath>> musicsSet;
/// stored position, in seconds at which music player should resume playing this track
std::map<std::string, float> trackPositions;
std::map<AudioPath, 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 & musicURI);
void addEntryToSet(const std::string & set, const AudioPath & musicURI);
void init() override;
void loadTerrainMusicThemes();
@ -156,7 +152,7 @@ public:
void setVolume(ui32 percent) override;
/// play track by URI, if loop = true music will be looped
void playMusic(const std::string & musicURI, bool loop, bool fromStart);
void playMusic(const AudioPath & musicURI, bool loop, bool fromStart);
/// play random track from this set
void playMusicFromSet(const std::string & musicSet, bool loop, bool fromStart);
/// play random track from set (musicSet, entryID)

View File

@ -1657,7 +1657,7 @@ void CPlayerInterface::viewWorldMap()
adventureInt->openWorldView();
}
void CPlayerInterface::advmapSpellCast(const CGHeroInstance * caster, int spellID)
void CPlayerInterface::advmapSpellCast(const CGHeroInstance * caster, SpellID spellID)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
@ -1667,8 +1667,7 @@ void CPlayerInterface::advmapSpellCast(const CGHeroInstance * caster, int spellI
if(spellID == SpellID::FLY || spellID == SpellID::WATER_WALK)
localState->erasePath(caster);
const spells::Spell * spell = CGI->spells()->getByIndex(spellID);
auto castSoundPath = spell->getCastSound();
auto castSoundPath = spellID.toSpell()->getCastSound();
if(!castSoundPath.empty())
CCS->soundh->playSound(castSoundPath);
}
@ -1992,22 +1991,22 @@ void CPlayerInterface::doMoveHero(const CGHeroInstance * h, CGPath path)
elem.coord = h->convertFromVisitablePos(elem.coord);
int soundChannel = -1;
std::string soundName;
AudioPath soundName;
auto getMovementSoundFor = [&](const CGHeroInstance * hero, int3 posPrev, int3 posNext, EPathNodeAction moveType) -> std::string
auto getMovementSoundFor = [&](const CGHeroInstance * hero, int3 posPrev, int3 posNext, EPathNodeAction moveType) -> AudioPath
{
if (moveType == EPathNodeAction::TELEPORT_BATTLE || moveType == EPathNodeAction::TELEPORT_BLOCKING_VISIT || moveType == EPathNodeAction::TELEPORT_NORMAL)
return "";
return {};
if (moveType == EPathNodeAction::EMBARK || moveType == EPathNodeAction::DISEMBARK)
return "";
return {};
if (moveType == EPathNodeAction::BLOCKING_VISIT)
return "";
return {};
// flying movement sound
if (hero->hasBonusOfType(BonusType::FLYING_MOVEMENT))
return "HORSE10.wav";
return AudioPath::builtin("HORSE10.wav");
auto prevTile = cb->getTile(h->convertToVisitablePos(posPrev));
auto nextTile = cb->getTile(h->convertToVisitablePos(posNext));
@ -2073,7 +2072,7 @@ void CPlayerInterface::doMoveHero(const CGHeroInstance * h, CGPath path)
{
// Start a new sound for the hero movement or let the existing one carry on.
std::string newSoundName = getMovementSoundFor(h, prevCoord, nextCoord, path.nodes[i-1].action);
AudioPath newSoundName = getMovementSoundFor(h, prevCoord, nextCoord, path.nodes[i-1].action);
if(newSoundName != soundName)
{

View File

@ -128,7 +128,7 @@ protected: // Call-ins from server, should not be called directly, but only via
void showMarketWindow(const IMarket *market, const CGHeroInstance *visitor) override;
void showUniversityWindow(const IMarket *market, const CGHeroInstance *visitor) override;
void showHillFortWindow(const CGObjectInstance *object, const CGHeroInstance *visitor) override;
void advmapSpellCast(const CGHeroInstance * caster, int spellID) override; //called when a hero casts a spell
void advmapSpellCast(const CGHeroInstance * caster, SpellID spellID) override; //called when a hero casts a spell
void tileHidden(const std::unordered_set<int3> &pos) override; //called when given tiles become hidden under fog of war
void tileRevealed(const std::unordered_set<int3> &pos) override; //called when fog of war disappears from given tiles
void newObject(const CGObjectInstance * obj) override;

View File

@ -105,7 +105,7 @@ void CInGameConsole::print(const std::string & txt)
}
GH.windows().totalRedraw(); // FIXME: ingame console has no parent widget set
CCS->soundh->playSound("CHAT");
CCS->soundh->playSound(AudioPath::builtin("CHAT"));
}
bool CInGameConsole::captureThisKey(EShortcut key)

View File

@ -123,9 +123,9 @@ void MapAudioPlayer::removeObject(const CGObjectInstance * obj)
vstd::erase(objects[z][x][y], obj->id);
}
std::vector<std::string> MapAudioPlayer::getAmbientSounds(const int3 & tile)
std::vector<AudioPath> MapAudioPlayer::getAmbientSounds(const int3 & tile)
{
std::vector<std::string> result;
std::vector<AudioPath> result;
for(auto & objectID : objects[tile.z][tile.x][tile.y])
{
@ -147,8 +147,8 @@ std::vector<std::string> MapAudioPlayer::getAmbientSounds(const int3 & tile)
void MapAudioPlayer::updateAmbientSounds()
{
std::map<std::string, int> currentSounds;
auto updateSounds = [&](const std::string& soundId, int distance) -> void
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);

View File

@ -10,6 +10,7 @@
#pragma once
#include "../mapView/IMapRendererObserver.h"
#include "../../lib/filesystem/ResourcePath.h"
VCMI_LIB_NAMESPACE_BEGIN
class ObjectInstanceID;
@ -29,7 +30,7 @@ class MapAudioPlayer : public IMapObjectObserver
void addObject(const CGObjectInstance * obj);
void removeObject(const CGObjectInstance * obj);
std::vector<std::string> getAmbientSounds(const int3 & tile);
std::vector<AudioPath> getAmbientSounds(const int3 & tile);
void updateAmbientSounds();
void updateMusic();
void update();

View File

@ -77,7 +77,7 @@ void TurnTimerWidget::setTime(PlayerColor player, int time)
&& newTime != turnTime
&& notifications.count(newTime))
{
CCS->soundh->playSound(variables["notificationSound"].String());
CCS->soundh->playSound(AudioPath::fromJson(variables["notificationSound"]));
}
turnTime = newTime;

View File

@ -114,7 +114,7 @@ void StackActionAnimation::setGroup( ECreatureAnimType group )
currGroup = group;
}
void StackActionAnimation::setSound( std::string sound )
void StackActionAnimation::setSound( const AudioPath & sound )
{
this->sound = sound;
}
@ -179,7 +179,7 @@ HittedAnimation::HittedAnimation(BattleInterface & owner, const CStack * stack)
: StackActionAnimation(owner, stack)
{
setGroup(ECreatureAnimType::HITTED);
setSound(battle_sound(stack->unitType(), wince));
setSound(stack->unitType()->sounds.wince);
logAnim->debug("Created HittedAnimation for %s", stack->getName());
}
@ -187,14 +187,14 @@ DefenceAnimation::DefenceAnimation(BattleInterface & owner, const CStack * stack
: StackActionAnimation(owner, stack)
{
setGroup(ECreatureAnimType::DEFENCE);
setSound(battle_sound(stack->unitType(), defend));
setSound(stack->unitType()->sounds.defend);
logAnim->debug("Created DefenceAnimation for %s", stack->getName());
}
DeathAnimation::DeathAnimation(BattleInterface & owner, const CStack * stack, bool ranged):
StackActionAnimation(owner, stack)
{
setSound(battle_sound(stack->unitType(), killed));
setSound(stack->unitType()->sounds.killed);
if(ranged && myAnim->framesInGroup(ECreatureAnimType::DEATH_RANGED) > 0)
setGroup(ECreatureAnimType::DEATH_RANGED);
@ -315,7 +315,7 @@ MeleeAttackAnimation::MeleeAttackAnimation(BattleInterface & owner, const CStack
: AttackAnimation(owner, attacker, _dest, _attacked)
{
logAnim->debug("Created MeleeAttackAnimation for %s", attacker->getName());
setSound(battle_sound(getCreature(), attack));
setSound(getCreature()->sounds.attack);
setGroup(selectGroup(multiAttack));
}
@ -356,7 +356,7 @@ bool MovementAnimation::init()
if (moveSoundHander == -1)
{
moveSoundHander = CCS->soundh->playSound(battle_sound(stack->unitType(), move), -1);
moveSoundHander = CCS->soundh->playSound(stack->unitType()->sounds.move, -1);
}
Point begPosition = owner.stacksController->getStackPositionAtHex(prevHex, stack);
@ -453,7 +453,7 @@ bool MovementEndAnimation::init()
logAnim->debug("CMovementEndAnimation::init: stack %s", stack->getName());
myAnim->pos.moveTo(owner.stacksController->getStackPositionAtHex(nextHex, stack));
CCS->soundh->playSound(battle_sound(stack->unitType(), endMoving));
CCS->soundh->playSound(stack->unitType()->sounds.endMoving);
if(!myAnim->framesInGroup(ECreatureAnimType::MOVE_END))
{
@ -494,7 +494,7 @@ bool MovementStartAnimation::init()
}
logAnim->debug("CMovementStartAnimation::init: stack %s", stack->getName());
CCS->soundh->playSound(battle_sound(stack->unitType(), startMoving));
CCS->soundh->playSound(stack->unitType()->sounds.startMoving);
if(!myAnim->framesInGroup(ECreatureAnimType::MOVE_START))
{
@ -632,7 +632,7 @@ RangedAttackAnimation::RangedAttackAnimation(BattleInterface & owner_, const CSt
: AttackAnimation(owner_, attacker, dest_, defender),
projectileEmitted(false)
{
setSound(battle_sound(getCreature(), shoot));
setSound(getCreature()->sounds.shoot);
}
bool RangedAttackAnimation::init()
@ -806,7 +806,7 @@ void CatapultAnimation::tick(uint32_t msPassed)
explosionEmitted = true;
Point shotTarget = owner.stacksController->getStackPositionAtHex(dest, defendingStack) + Point(225, 225) - Point(126, 105);
std::string soundFilename = (catapultDamage > 0) ? "WALLHIT" : "WALLMISS";
auto soundFilename = AudioPath::builtin((catapultDamage > 0) ? "WALLHIT" : "WALLMISS");
AnimationPath effectFilename = AnimationPath::builtin((catapultDamage > 0) ? "SGEXPL" : "CSGRCK");
CCS->soundh->playSound( soundFilename );

View File

@ -69,11 +69,11 @@ class StackActionAnimation : public BattleStackAnimation
{
ECreatureAnimType nextGroup;
ECreatureAnimType currGroup;
std::string sound;
AudioPath sound;
public:
void setNextGroup( ECreatureAnimType group );
void setGroup( ECreatureAnimType group );
void setSound( std::string sound );
void setSound( const AudioPath & sound );
ECreatureAnimType getGroup() const;

View File

@ -41,10 +41,10 @@ BattleEffectsController::BattleEffectsController(BattleInterface & owner):
void BattleEffectsController::displayEffect(EBattleEffect effect, const BattleHex & destTile)
{
displayEffect(effect, "", destTile);
displayEffect(effect, AudioPath(), destTile);
}
void BattleEffectsController::displayEffect(EBattleEffect effect, std::string soundFile, const BattleHex & destTile)
void BattleEffectsController::displayEffect(EBattleEffect effect, const AudioPath & soundFile, const BattleHex & destTile)
{
size_t effectID = static_cast<size_t>(effect);
@ -69,22 +69,22 @@ void BattleEffectsController::battleTriggerEffect(const BattleTriggerEffect & bt
switch(static_cast<BonusType>(bte.effect))
{
case BonusType::HP_REGENERATION:
displayEffect(EBattleEffect::REGENERATION, "REGENER", stack->getPosition());
displayEffect(EBattleEffect::REGENERATION, AudioPath::builtin("REGENER"), stack->getPosition());
break;
case BonusType::MANA_DRAIN:
displayEffect(EBattleEffect::MANA_DRAIN, "MANADRAI", stack->getPosition());
displayEffect(EBattleEffect::MANA_DRAIN, AudioPath::builtin("MANADRAI"), stack->getPosition());
break;
case BonusType::POISON:
displayEffect(EBattleEffect::POISON, "POISON", stack->getPosition());
displayEffect(EBattleEffect::POISON, AudioPath::builtin("POISON"), stack->getPosition());
break;
case BonusType::FEAR:
displayEffect(EBattleEffect::FEAR, "FEAR", stack->getPosition());
displayEffect(EBattleEffect::FEAR, AudioPath::builtin("FEAR"), stack->getPosition());
break;
case BonusType::MORALE:
{
std::string hlp = CGI->generaltexth->allTexts[33];
boost::algorithm::replace_first(hlp,"%s",(stack->getName()));
displayEffect(EBattleEffect::GOOD_MORALE, "GOODMRLE", stack->getPosition());
displayEffect(EBattleEffect::GOOD_MORALE, AudioPath::builtin("GOODMRLE"), stack->getPosition());
owner.appendBattleLog(hlp);
break;
}
@ -107,7 +107,7 @@ void BattleEffectsController::startAction(const BattleAction & action)
break;
case EActionType::BAD_MORALE:
owner.appendBattleLog(stack->formatGeneralMessage(-34));
displayEffect(EBattleEffect::BAD_MORALE, "BADMRLE", stack->getPosition());
displayEffect(EBattleEffect::BAD_MORALE, AudioPath::builtin("BADMRLE"), stack->getPosition());
break;
}

View File

@ -11,6 +11,7 @@
#include "../../lib/battle/BattleHex.h"
#include "../../lib/Point.h"
#include "../../lib/filesystem/ResourcePath.h"
#include "BattleConstants.h"
VCMI_LIB_NAMESPACE_BEGIN
@ -64,7 +65,7 @@ public:
//displays custom effect on the battlefield
void displayEffect(EBattleEffect effect, const BattleHex & destTile);
void displayEffect(EBattleEffect effect, std::string soundFile, const BattleHex & destTile);
void displayEffect(EBattleEffect effect, const AudioPath & soundFile, const BattleHex & destTile);
void battleTriggerEffect(const BattleTriggerEffect & bte);

View File

@ -353,7 +353,7 @@ void BattleInterface::spellCast(const BattleSpellCast * sc)
if(!spell)
return;
const std::string & castSoundPath = spell->getCastSound();
const AudioPath & castSoundPath = spell->getCastSound();
if (!castSoundPath.empty())
{
@ -419,7 +419,7 @@ void BattleInterface::spellCast(const BattleSpellCast * sc)
if (!sc->resistedCres.empty())
{
addToAnimationStage(EAnimationEvents::HIT, [=](){
CCS->soundh->playSound("MAGICRES");
CCS->soundh->playSound(AudioPath::builtin("MAGICRES"));
});
}

View File

@ -580,7 +580,7 @@ BattleResultWindow::BattleResultWindow(const BattleResult & br, CPlayerInterface
break;
}
CCS->musich->playMusic("Music/Win Battle", false, true);
CCS->musich->playMusic(AudioPath::builtin("Music/Win Battle"), false, true);
CCS->videoh->open(VideoPath::builtin("WIN3.BIK"));
std::string str = CGI->generaltexth->allTexts[text];
@ -597,19 +597,19 @@ BattleResultWindow::BattleResultWindow(const BattleResult & br, CPlayerInterface
else // we lose
{
int text = 311;
std::string musicName = "Music/LoseCombat";
AudioPath musicName = AudioPath::builtin("Music/LoseCombat");
VideoPath videoName = VideoPath::builtin("LBSTART.BIK");
switch(br.result)
{
case EBattleResult::NORMAL:
break;
case EBattleResult::ESCAPE:
musicName = "Music/Retreat Battle";
musicName = AudioPath::builtin("Music/Retreat Battle");
videoName = VideoPath::builtin("RTSTART.BIK");
text = 310;
break;
case EBattleResult::SURRENDER:
musicName = "Music/Surrender Battle";
musicName = AudioPath::builtin("Music/Surrender Battle");
videoName = VideoPath::builtin("SURRENDER.BIK");
text = 309;
break;

View File

@ -340,7 +340,7 @@ void BattleSiegeController::stackIsCatapulting(const CatapultAttack & ca)
for (auto attackInfo : ca.attackedParts)
positions.push_back(owner.stacksController->getStackPositionAtHex(attackInfo.destinationTile, nullptr) + Point(99, 120));
CCS->soundh->playSound( "WALLHIT" );
CCS->soundh->playSound( AudioPath::builtin("WALLHIT") );
owner.stacksController->addNewAnim(new EffectAnimation(owner, AnimationPath::builtin("SGEXPL.DEF"), positions));
}

View File

@ -462,7 +462,7 @@ void BattleStacksController::stacksAreAttacked(std::vector<StackAttackedInfo> at
addNewAnim(new HittedAnimation(owner, attackedInfo.defender));
if (attackedInfo.fireShield)
owner.effectsController->displayEffect(EBattleEffect::FIRE_SHIELD, "FIRESHIE", attackedInfo.attacker->getPosition());
owner.effectsController->displayEffect(EBattleEffect::FIRE_SHIELD, AudioPath::builtin("FIRESHIE"), attackedInfo.attacker->getPosition());
if (attackedInfo.spellEffect != SpellID::NONE)
{
@ -481,7 +481,7 @@ void BattleStacksController::stacksAreAttacked(std::vector<StackAttackedInfo> at
if (attackedInfo.rebirth)
{
owner.addToAnimationStage(EAnimationEvents::AFTER_HIT, [=](){
owner.effectsController->displayEffect(EBattleEffect::RESURRECT, "RESURECT", attackedInfo.defender->getPosition());
owner.effectsController->displayEffect(EBattleEffect::RESURRECT, AudioPath::builtin("RESURECT"), attackedInfo.defender->getPosition());
addNewAnim(new ResurrectionAnimation(owner, attackedInfo.defender));
});
}
@ -594,7 +594,7 @@ void BattleStacksController::stackAttacking( const StackAttackInfo & info )
{
owner.addToAnimationStage(EAnimationEvents::BEFORE_HIT, [=]() {
owner.appendBattleLog(info.attacker->formatGeneralMessage(-45));
owner.effectsController->displayEffect(EBattleEffect::GOOD_LUCK, "GOODLUCK", attacker->getPosition());
owner.effectsController->displayEffect(EBattleEffect::GOOD_LUCK, AudioPath::builtin("GOODLUCK"), attacker->getPosition());
});
}
@ -602,7 +602,7 @@ void BattleStacksController::stackAttacking( const StackAttackInfo & info )
{
owner.addToAnimationStage(EAnimationEvents::BEFORE_HIT, [=]() {
owner.appendBattleLog(info.attacker->formatGeneralMessage(-44));
owner.effectsController->displayEffect(EBattleEffect::BAD_LUCK, "BADLUCK", attacker->getPosition());
owner.effectsController->displayEffect(EBattleEffect::BAD_LUCK, AudioPath::builtin("BADLUCK"), attacker->getPosition());
});
}
@ -610,7 +610,7 @@ void BattleStacksController::stackAttacking( const StackAttackInfo & info )
{
owner.addToAnimationStage(EAnimationEvents::BEFORE_HIT, [=]() {
owner.appendBattleLog(info.attacker->formatGeneralMessage(365));
owner.effectsController->displayEffect(EBattleEffect::DEATH_BLOW, "DEATHBLO", defender->getPosition());
owner.effectsController->displayEffect(EBattleEffect::DEATH_BLOW, AudioPath::builtin("DEATHBLO"), defender->getPosition());
});
for(auto elem : info.secondaryDefender)
@ -645,7 +645,7 @@ void BattleStacksController::stackAttacking( const StackAttackInfo & info )
{
owner.addToAnimationStage(EAnimationEvents::AFTER_HIT, [=]()
{
owner.effectsController->displayEffect(EBattleEffect::DRAIN_LIFE, "DRAINLIF", attacker->getPosition());
owner.effectsController->displayEffect(EBattleEffect::DRAIN_LIFE, AudioPath::builtin("DRAINLIF"), attacker->getPosition());
});
}

View File

@ -114,7 +114,7 @@ CBonusSelection::CBonusSelection()
}
if (!getCampaign()->getMusic().empty())
CCS->musich->playMusic( "Music/" + getCampaign()->getMusic(), true, false);
CCS->musich->playMusic( getCampaign()->getMusic(), true, false);
}
void CBonusSelection::createBonusesIcons()

View File

@ -339,7 +339,7 @@ void CChatBox::keyPressed(EShortcut key)
void CChatBox::addNewMessage(const std::string & text)
{
CCS->soundh->playSound("CHAT");
CCS->soundh->playSound(AudioPath::builtin("CHAT"));
chatHistory->setText(chatHistory->label->getText() + text + "\n");
if(chatHistory->slider)
chatHistory->slider->scrollToMax();

View File

@ -75,7 +75,7 @@ CCampaignScreen::CCampaignScreen(const JsonNode & config)
void CCampaignScreen::activate()
{
CCS->musich->playMusic("Music/MainMenu", true, false);
CCS->musich->playMusic(AudioPath::builtin("Music/MainMenu"), true, false);
CWindowObject::activate();
}
@ -129,12 +129,12 @@ void CCampaignScreen::CCampaignButton::show(Canvas & to)
// Play the campaign button video when the mouse cursor is placed over the button
if(isHovered())
{
if(CCS->videoh->fname != video)
if(CCS->videoh->fname != video.addPrefix("VIDEO/"))
CCS->videoh->open(video);
CCS->videoh->update(pos.x, pos.y, to.getInternalSurface(), true, false); // plays sequentially frame by frame, starts at the beginning when the video is over
}
else if(CCS->videoh->fname == video) // When you got out of the bounds of the button then close the video
else if(CCS->videoh->fname == video.addPrefix("VIDEO/")) // When you got out of the bounds of the button then close the video
{
CCS->videoh->close();
redraw();

View File

@ -114,7 +114,7 @@ void CMenuScreen::show(Canvas & to)
void CMenuScreen::activate()
{
CCS->musich->playMusic("Music/MainMenu", true, true);
CCS->musich->playMusic(AudioPath::builtin("Music/MainMenu"), true, true);
if(!config["video"].isNull())
CCS->videoh->open(VideoPath::fromJson(config["video"]["name"]));
CIntObject::activate();

View File

@ -28,7 +28,7 @@ CPrologEpilogVideo::CPrologEpilogVideo(CampaignScenarioPrologEpilog _spe, std::f
updateShadow();
CCS->videoh->open(spe.prologVideo);
CCS->musich->playMusic("Music/" + spe.prologMusic, true, true);
CCS->musich->playMusic(spe.prologMusic, true, true);
// MPTODO: Custom campaign crashing on this?
// voiceSoundHandle = CCS->soundh->playSound(CCampaignHandler::prologVoiceName(spe.prologVideo));

View File

@ -182,7 +182,7 @@ void CAnimation::init()
if (vstd::contains(graphics->imageLists, name.getName()))
initFromJson(graphics->imageLists[name.getName()]);
auto jsonResource = name.toType<EResType::TEXT>();
auto jsonResource = name.toType<EResType::JSON>();
auto configList = CResourceHandler::get()->getResourcesWithName(jsonResource);
for(auto & loader : configList)

View File

@ -45,7 +45,6 @@ public:
virtual bool hasSchool(SpellSchool school) const = 0;
virtual void forEachSchool(const SchoolCallback & cb) const = 0;
virtual const std::string & getCastSound() const = 0;
virtual int32_t getCost(const int32_t skillLevel) const = 0;
virtual int32_t getBasePower() const = 0;

View File

@ -955,17 +955,14 @@ void CCreatureHandler::loadCreatureJson(CCreature * creature, const JsonNode & c
creature->special = config["special"].Bool() || config["disabled"].Bool();
const JsonNode & sounds = config["sound"];
#define GET_SOUND_VALUE(value_name) creature->sounds.value_name = sounds[#value_name].String()
GET_SOUND_VALUE(attack);
GET_SOUND_VALUE(defend);
GET_SOUND_VALUE(killed);
GET_SOUND_VALUE(move);
GET_SOUND_VALUE(shoot);
GET_SOUND_VALUE(wince);
GET_SOUND_VALUE(startMoving);
GET_SOUND_VALUE(endMoving);
#undef GET_SOUND_VALUE
creature->sounds.attack = AudioPath::fromJson(sounds["attack"]);
creature->sounds.defend = AudioPath::fromJson(sounds["defend"]);
creature->sounds.killed = AudioPath::fromJson(sounds["killed"]);
creature->sounds.move = AudioPath::fromJson(sounds["move"]);
creature->sounds.shoot = AudioPath::fromJson(sounds["shoot"]);
creature->sounds.wince = AudioPath::fromJson(sounds["wince"]);
creature->sounds.startMoving = AudioPath::fromJson(sounds["startMoving"]);
creature->sounds.endMoving = AudioPath::fromJson(sounds["endMoving"]);
}
void CCreatureHandler::loadStackExperience(CCreature * creature, const JsonNode & input) const

View File

@ -132,14 +132,14 @@ public:
//sound info
struct CreatureBattleSounds
{
std::string attack;
std::string defend;
std::string killed; // was killed or died
std::string move;
std::string shoot; // range attack
std::string wince; // attacked but did not die
std::string startMoving;
std::string endMoving;
AudioPath attack;
AudioPath defend;
AudioPath killed; // was killed or died
AudioPath move;
AudioPath shoot; // range attack
AudioPath wince; // attacked but did not die
AudioPath startMoving;
AudioPath endMoving;
template <typename Handler> void serialize(Handler &h, const int version)
{

View File

@ -48,7 +48,7 @@ void CGeneralTextHandler::detectInstallParameters()
"ukrainian"
} };
if(!CResourceHandler::get("core")->existsResource(ResourcePath("DATA/GENRLTXT.TXT", EResType::TEXT)))
if(!CResourceHandler::get("core")->existsResource(TextPath::builtin("DATA/GENRLTXT.TXT")))
{
Settings language = settings.write["session"]["language"];
language->String() = "english";
@ -64,7 +64,7 @@ void CGeneralTextHandler::detectInstallParameters()
// load file that will be used for footprint generation
// this is one of the most text-heavy files in game and consists solely from translated texts
auto resource = CResourceHandler::get("core")->load(ResourcePath("DATA/GENRLTXT.TXT", EResType::TEXT));
auto resource = CResourceHandler::get("core")->load(TextPath::builtin("DATA/GENRLTXT.TXT"));
std::array<size_t, 256> charCount{};
std::array<double, 16> footprint{};
@ -429,7 +429,7 @@ CGeneralTextHandler::CGeneralTextHandler():
readToVector("core.mineevnt", "DATA/MINEEVNT.TXT" );
static const char * QE_MOD_COMMANDS = "DATA/QECOMMANDS.TXT";
if (CResourceHandler::get()->existsResource(ResourcePath(QE_MOD_COMMANDS, EResType::TEXT)))
if (CResourceHandler::get()->existsResource(TextPath::builtin(QE_MOD_COMMANDS)))
readToVector("vcmi.quickExchange", QE_MOD_COMMANDS);
{
@ -574,7 +574,7 @@ CGeneralTextHandler::CGeneralTextHandler():
}
if (VLC->settings()->getBoolean(EGameSettings::MODULE_COMMANDERS))
{
if(CResourceHandler::get()->existsResource(ResourcePath("DATA/ZNPC00.TXT", EResType::TEXT)))
if(CResourceHandler::get()->existsResource(TextPath::builtin("DATA/ZNPC00.TXT")))
readToVector("vcmi.znpc00", "DATA/ZNPC00.TXT" );
}
}

View File

@ -878,7 +878,7 @@ void CTownHandler::loadClientData(CTown &town, const JsonNode & source) const
readIcon(source["icons"]["fort"]["built"], info.iconSmall[1][1], info.iconLarge[1][1]);
info.hallBackground = ImagePath::fromJson(source["hallBackground"]);
info.musicTheme = source["musicTheme"].String();
info.musicTheme = AudioPath::fromJson(source["musicTheme"]);
info.townBackground = ImagePath::fromJson(source["townBackground"]);
info.guildWindow = ImagePath::fromJson(source["guildWindow"]);
info.buildingsIcons = AnimationPath::fromJson(source["buildingsIcons"]);

View File

@ -305,7 +305,7 @@ public:
std::string iconSmall[2][2]; /// icon names used during loading
std::string iconLarge[2][2];
VideoPath tavernVideo;
std::string musicTheme;
AudioPath musicTheme;
ImagePath townBackground;
ImagePath guildBackground;
ImagePath guildWindow;

View File

@ -116,7 +116,7 @@ public:
virtual void showTavernWindow(const CGObjectInstance *townOrTavern){};
virtual void showThievesGuildWindow (const CGObjectInstance * obj){};
virtual void showQuestLog(){};
virtual void advmapSpellCast(const CGHeroInstance * caster, int spellID){}; //called when a hero casts a spell
virtual void advmapSpellCast(const CGHeroInstance * caster, SpellID spellID){}; //called when a hero casts a spell
virtual void tileHidden(const std::unordered_set<int3> &pos){};
virtual void tileRevealed(const std::unordered_set<int3> &pos){};
virtual void newObject(const CGObjectInstance * obj){}; //eg. ship built in shipyard

View File

@ -1036,13 +1036,13 @@ namespace
std::string testAnimation(const std::string & path, const std::string & scope)
{
TEST_FILE(scope, "Sprites/", path, EResType::ANIMATION);
TEST_FILE(scope, "Sprites/", path, EResType::TEXT);
TEST_FILE(scope, "Sprites/", path, EResType::JSON);
return "Animation file \"" + path + "\" was not found";
}
std::string textFile(const JsonNode & node)
{
TEST_FILE(node.meta, "", node.String(), EResType::TEXT);
TEST_FILE(node.meta, "", node.String(), EResType::JSON);
return "Text file \"" + node.String() + "\" was not found";
}

View File

@ -32,7 +32,7 @@ public:
Obstacle obstacle;
si32 iconIndex;
std::string identifier;
std::string appearSound;
AudioPath appearSound;
AnimationPath appearAnimation;
AnimationPath animation;
std::vector<TerrainId> allowedTerrains;

View File

@ -27,10 +27,10 @@ TerrainType * TerrainTypeHandler::loadFromJson( const std::string & scope, const
info->identifier = identifier;
info->modScope = scope;
info->moveCost = static_cast<int>(json["moveCost"].Integer());
info->musicFilename = json["music"].String();
info->musicFilename = AudioPath::fromJson(json["music"]);
info->tilesFilename = AnimationPath::fromJson(json["tiles"]);
info->horseSound = json["horseSound"].String();
info->horseSoundPenalty = json["horseSoundPenalty"].String();
info->horseSound = AudioPath::fromJson(json["horseSound"]);
info->horseSoundPenalty = AudioPath::fromJson(json["horseSoundPenalty"]);
info->transitionRequired = json["transitionRequired"].Bool();
info->terrainViewPatterns = json["terrainViewPatterns"].String();

View File

@ -67,11 +67,11 @@ public:
ColorRGBA minimapBlocked;
ColorRGBA minimapUnblocked;
std::string shortIdentifier;
std::string musicFilename;
AudioPath musicFilename;
AnimationPath tilesFilename;
std::string terrainViewPatterns;
std::string horseSound;
std::string horseSoundPenalty;
AudioPath horseSound;
AudioPath horseSoundPenalty;
std::vector<TerrainPaletteAnimation> paletteAnimation;

View File

@ -70,7 +70,7 @@ const AnimationPath & CObstacleInstance::getAppearAnimation() const
return getInfo().appearAnimation;
}
const std::string & CObstacleInstance::getAppearSound() const
const AudioPath & CObstacleInstance::getAppearSound() const
{
return getInfo().appearSound;
}
@ -118,7 +118,7 @@ void CObstacleInstance::serializeJson(JsonSerializeFormat & handler)
//We need only a subset of obstacle info for correct render
handler.serializeInt("position", pos);
handler.serializeString("appearSound", obstacleInfo.appearSound);
handler.serializeStruct("appearSound", obstacleInfo.appearSound);
handler.serializeStruct("appearAnimation", obstacleInfo.appearAnimation);
handler.serializeStruct("animation", obstacleInfo.animation);
handler.serializeInt("animationYOffset", animationYOffset);
@ -213,7 +213,7 @@ void SpellCreatedObstacle::serializeJson(JsonSerializeFormat & handler)
handler.serializeBool("removeOnTrigger", removeOnTrigger);
handler.serializeBool("nativeVisible", nativeVisible);
handler.serializeString("appearSound", appearSound);
handler.serializeStruct("appearSound", appearSound);
handler.serializeStruct("appearAnimation", appearAnimation);
handler.serializeStruct("animation", animation);
@ -249,7 +249,7 @@ const AnimationPath & SpellCreatedObstacle::getAppearAnimation() const
return appearAnimation;
}
const std::string & SpellCreatedObstacle::getAppearSound() const
const AudioPath & SpellCreatedObstacle::getAppearSound() const
{
return appearSound;
}

View File

@ -54,7 +54,7 @@ struct DLL_LINKAGE CObstacleInstance
//Client helper functions, make it easier to render animations
virtual const AnimationPath & getAnimation() const;
virtual const AnimationPath & getAppearAnimation() const;
virtual const std::string & getAppearSound() const;
virtual const AudioPath & getAppearSound() const;
virtual int getAnimationYOffset(int imageHeight) const;
@ -88,7 +88,7 @@ struct DLL_LINKAGE SpellCreatedObstacle : CObstacleInstance
bool revealed;
bool nativeVisible; //Should native terrain creatures reveal obstacle
std::string appearSound;
AudioPath appearSound;
AnimationPath appearAnimation;
AnimationPath animation;
@ -110,7 +110,7 @@ struct DLL_LINKAGE SpellCreatedObstacle : CObstacleInstance
//Client helper functions, make it easier to render animations
const AnimationPath & getAnimation() const override;
const AnimationPath & getAppearAnimation() const override;
const std::string & getAppearSound() const override;
const AudioPath & getAppearSound() const override;
int getAnimationYOffset(int imageHeight) const override;
void fromInfo(const ObstacleChanges & info);

View File

@ -152,7 +152,7 @@ void CampaignHandler::readHeaderFromJson(CampaignHeader & ret, JsonNode & reader
ret.name = reader["name"].String();
ret.description = reader["description"].String();
ret.difficultyChoosenByPlayer = reader["allowDifficultySelection"].Bool();
ret.music = reader["music"].String();
ret.music = AudioPath::fromJson(reader["music"]);
ret.filename = filename;
ret.modName = modName;
ret.encoding = encoding;
@ -167,7 +167,7 @@ CampaignScenario CampaignHandler::readScenarioFromJson(JsonNode & reader)
if(ret.hasPrologEpilog)
{
ret.prologVideo = VideoPath::fromJson(identifier["video"]);
ret.prologMusic = identifier["music"].String();
ret.prologMusic = AudioPath::fromJson(identifier["music"]);
ret.prologText = identifier["text"].String();
}
return ret;
@ -599,10 +599,10 @@ VideoPath CampaignHandler::prologVideoName(ui8 index)
return VideoPath();
}
std::string CampaignHandler::prologMusicName(ui8 index)
AudioPath CampaignHandler::prologMusicName(ui8 index)
{
std::vector<std::string> music;
return VLC->generaltexth->translate("core.cmpmusic." + std::to_string(static_cast<int>(index)));
return AudioPath::builtinTODO(VLC->generaltexth->translate("core.cmpmusic." + std::to_string(static_cast<int>(index))));
}
std::string CampaignHandler::prologVoiceName(ui8 index)

View File

@ -34,7 +34,7 @@ class DLL_LINKAGE CampaignHandler
static std::vector<std::vector<ui8>> getFile(std::unique_ptr<CInputStream> file, bool headerOnly);
static VideoPath prologVideoName(ui8 index);
static std::string prologMusicName(ui8 index);
static AudioPath prologMusicName(ui8 index);
static std::string prologVoiceName(ui8 index);
public:

View File

@ -17,7 +17,7 @@ struct DLL_LINKAGE CampaignScenarioPrologEpilog
{
bool hasPrologEpilog = false;
VideoPath prologVideo; // from CmpMovie.txt
std::string prologMusic; // from CmpMusic.txt
AudioPath prologMusic; // from CmpMusic.txt
std::string prologText;
template <typename Handler> void serialize(Handler &h, const int formatVersion)

View File

@ -159,7 +159,7 @@ std::string CampaignHeader::getEncoding() const
return encoding;
}
std::string CampaignHeader::getMusic() const
AudioPath CampaignHeader::getMusic() const
{
return music;
}

View File

@ -76,7 +76,7 @@ class DLL_LINKAGE CampaignHeader : public boost::noncopyable
CampaignRegions campaignRegions;
std::string name;
std::string description;
std::string music;
AudioPath music;
std::string filename;
std::string modName;
std::string encoding;
@ -95,7 +95,7 @@ public:
std::string getFilename() const;
std::string getModName() const;
std::string getEncoding() const;
std::string getMusic() const;
AudioPath getMusic() const;
const CampaignRegions & getRegions() const;

View File

@ -103,7 +103,7 @@ std::unordered_map<ResourcePath, boost::filesystem::path> CFilesystemLoader::lis
{
static const EResType initArray[] = {
EResType::DIRECTORY,
EResType::TEXT,
EResType::JSON,
EResType::ARCHIVE_LOD,
EResType::ARCHIVE_VID,
EResType::ARCHIVE_SND,

View File

@ -113,10 +113,10 @@ void CFilesystemGenerator::loadArchive(const std::string &mountPoint, const Json
void CFilesystemGenerator::loadJsonMap(const std::string &mountPoint, const JsonNode & config)
{
std::string URI = prefix + config["path"].String();
auto filename = CResourceHandler::get("initial")->getResourceName(ResourcePath(URI, EResType::TEXT));
auto filename = CResourceHandler::get("initial")->getResourceName(JsonPath::builtin(URI));
if (filename)
{
auto configData = CResourceHandler::get("initial")->load(ResourcePath(URI, EResType::TEXT))->readAll();
auto configData = CResourceHandler::get("initial")->load(JsonPath::builtin(URI))->readAll();
const JsonNode configInitial(reinterpret_cast<char *>(configData.first.get()), configData.second);
filesystem->addLoader(new CMappedFileLoader(mountPoint, configInitial), false);
}
@ -210,7 +210,7 @@ ISimpleResourceLoader * CResourceHandler::get(const std::string & identifier)
void CResourceHandler::load(const std::string &fsConfigURI, bool extractArchives)
{
auto fsConfigData = get("initial")->load(ResourcePath(fsConfigURI, EResType::TEXT))->readAll();
auto fsConfigData = get("initial")->load(JsonPath::builtin(fsConfigURI))->readAll();
const JsonNode fsConfig(reinterpret_cast<char *>(fsConfigData.first.get()), fsConfigData.second);

View File

@ -94,7 +94,7 @@ EResType EResTypeHelper::getTypeFromExtension(std::string extension)
static const std::map<std::string, EResType> stringToRes =
{
{".TXT", EResType::TEXT},
{".JSON", EResType::TEXT},
{".JSON", EResType::JSON},
{".DEF", EResType::ANIMATION},
{".MSK", EResType::MASK},
{".MSG", EResType::MASK},
@ -148,6 +148,7 @@ std::string EResTypeHelper::getEResTypeAsString(EResType type)
static const std::map<EResType, std::string> stringToRes =
{
MAP_ENUM(TEXT)
MAP_ENUM(JSON)
MAP_ENUM(ANIMATION)
MAP_ENUM(MASK)
MAP_ENUM(CAMPAIGN)

View File

@ -140,6 +140,12 @@ public:
:ResourcePath("", Type)
{}
static ResourcePathTempl fromResource(const ResourcePath & resource)
{
assert(Type == resource.getType());
return ResourcePathTempl(resource);
}
static ResourcePathTempl builtin(const std::string & filename)
{
return ResourcePathTempl(filename, Type);
@ -177,6 +183,7 @@ using ImagePath = ResourcePathTempl<EResType::IMAGE>;
using TextPath = ResourcePathTempl<EResType::TEXT>;
using JsonPath = ResourcePathTempl<EResType::JSON>;
using VideoPath = ResourcePathTempl<EResType::VIDEO>;
using AudioPath = ResourcePathTempl<EResType::SOUND>;
namespace EResTypeHelper
{

View File

@ -83,13 +83,13 @@ void AObjectTypeHandler::init(const JsonNode & input)
}
for(const JsonNode & node : input["sounds"]["ambient"].Vector())
sounds.ambient.push_back(node.String());
sounds.ambient.push_back(AudioPath::fromJson(node));
for(const JsonNode & node : input["sounds"]["visit"].Vector())
sounds.visit.push_back(node.String());
sounds.visit.push_back(AudioPath::fromJson(node));
for(const JsonNode & node : input["sounds"]["removal"].Vector())
sounds.removal.push_back(node.String());
sounds.removal.push_back(AudioPath::fromJson(node));
if(input["aiValue"].isNull())
aiValue = std::nullopt;

View File

@ -9,13 +9,15 @@
*/
#pragma once
#include "../filesystem/ResourcePath.h"
VCMI_LIB_NAMESPACE_BEGIN
struct SObjectSounds
{
std::vector<std::string> ambient;
std::vector<std::string> visit;
std::vector<std::string> removal;
std::vector<AudioPath> ambient;
std::vector<AudioPath> visit;
std::vector<AudioPath> removal;
template <typename Handler> void serialize(Handler &h, const int version)
{

View File

@ -214,7 +214,7 @@ std::string CGObjectInstance::getObjectName() const
return VLC->objtypeh->getObjectName(ID, subID);
}
std::optional<std::string> CGObjectInstance::getAmbientSound() const
std::optional<AudioPath> CGObjectInstance::getAmbientSound() const
{
const auto & sounds = VLC->objtypeh->getObjectSounds(ID, subID).ambient;
if(!sounds.empty())
@ -223,7 +223,7 @@ std::optional<std::string> CGObjectInstance::getAmbientSound() const
return std::nullopt;
}
std::optional<std::string> CGObjectInstance::getVisitSound() const
std::optional<AudioPath> CGObjectInstance::getVisitSound() const
{
const auto & sounds = VLC->objtypeh->getObjectSounds(ID, subID).visit;
if(!sounds.empty())
@ -232,7 +232,7 @@ std::optional<std::string> CGObjectInstance::getVisitSound() const
return std::nullopt;
}
std::optional<std::string> CGObjectInstance::getRemovalSound() const
std::optional<AudioPath> CGObjectInstance::getRemovalSound() const
{
const auto & sounds = VLC->objtypeh->getObjectSounds(ID, subID).removal;
if(!sounds.empty())

View File

@ -82,9 +82,9 @@ public:
virtual bool isTile2Terrain() const { return false; }
std::optional<std::string> getAmbientSound() const;
std::optional<std::string> getVisitSound() const;
std::optional<std::string> getRemovalSound() const;
std::optional<AudioPath> getAmbientSound() const;
std::optional<AudioPath> getVisitSound() const;
std::optional<AudioPath> getRemovalSound() const;
/** VIRTUAL METHODS **/

View File

@ -904,7 +904,7 @@ std::unique_ptr<CMapHeader> CMapLoaderJson::loadMapHeader()
JsonNode CMapLoaderJson::getFromArchive(const std::string & archiveFilename)
{
ResourcePath resource(archiveFilename, EResType::TEXT);
JsonPath resource = JsonPath::builtin(archiveFilename);
if(!loader.existsResource(resource))
throw std::runtime_error(archiveFilename+" not found");

View File

@ -310,7 +310,7 @@ const std::string & CSpell::getIconScroll() const
return iconScroll;
}
const std::string & CSpell::getCastSound() const
const AudioPath & CSpell::getCastSound() const
{
return castSound;
}
@ -896,7 +896,7 @@ CSpell * CSpellHandler::loadFromJson(const std::string & scope, const JsonNode &
}
const JsonNode & soundsNode = json["sounds"];
spell->castSound = soundsNode["cast"].String();
spell->castSound = AudioPath::fromJson(soundsNode["cast"]);
//load level attributes
const int levelsCount = GameConstants::SPELL_SCHOOL_LEVELS;

View File

@ -262,7 +262,7 @@ public:
const std::string & getIconScenarioBonus() const;
const std::string & getIconScroll() const;
const std::string & getCastSound() const override;
const AudioPath & getCastSound() const;
void updateFrom(const JsonNode & data);
void serializeJson(JsonSerializeFormat & handler);
@ -354,7 +354,7 @@ private:
std::string iconScroll;
///sound related stuff
std::string castSound;
AudioPath castSound;
std::vector<LevelInfo> levels;

View File

@ -85,7 +85,7 @@ void ObstacleSideOptions::serializeJson(JsonSerializeFormat & handler)
serializeRelativeShape(handler, "shape", shape);
serializeRelativeShape(handler, "range", range);
handler.serializeString("appearSound", appearSound);
handler.serializeStruct("appearSound", appearSound);
handler.serializeStruct("appearAnimation", appearAnimation);
handler.serializeStruct("animation", animation);

View File

@ -30,7 +30,7 @@ public:
RelativeShape shape; //shape of single obstacle relative to obstacle position
RelativeShape range; //position of obstacles relative to effect destination
std::string appearSound;
AudioPath appearSound;
AnimationPath appearAnimation;
AnimationPath animation;

View File

@ -583,7 +583,7 @@ void Animation::init()
source[defEntry.first].resize(defEntry.second);
}
ResourcePath resID(std::string("SPRITES/") + name, EResType::TEXT);
JsonPath resID = JsonPath::builtin("SPRITES/" + name);
//if(vstd::contains(graphics->imageLists, resID.getName()))
//initFromJson(graphics->imageLists[resID.getName()]);

View File

@ -90,7 +90,7 @@ TEST(MapFormat, Random)
static JsonNode getFromArchive(CZipLoader & archive, const std::string & archiveFilename)
{
ResourcePath resource(archiveFilename, EResType::TEXT);
JsonPath resource = JsonPath::builtin(archiveFilename);
if(!archive.existsResource(resource))
throw std::runtime_error(archiveFilename + " not found");