Browse Source

Add StrCat and StrAppend

Adds simple string / integer concatenation functions.

Many of the uses of `fmt::format` are simply concatenation
of a few strings and integers.

`StrCat` is an easier-to-read alternative to such uses of `fmt`.
pull/4937/head
Gleb Mazovetskiy 4 years ago committed by Anders Jenbo
parent
commit
197e1180b2
  1. 1
      Source/CMakeLists.txt
  2. 3
      Source/DiabloUI/selgame.cpp
  3. 15
      Source/DiabloUI/selhero.cpp
  4. 3
      Source/appfat.cpp
  5. 9
      Source/control.cpp
  6. 3
      Source/controls/plrctrls.cpp
  7. 125
      Source/debug.cpp
  8. 5
      Source/discord/discord.cpp
  9. 5
      Source/effects.cpp
  10. 7
      Source/engine/load_file.hpp
  11. 5
      Source/engine/render/scrollrt.cpp
  12. 3
      Source/engine/sound.cpp
  13. 5
      Source/inv.cpp
  14. 15
      Source/items.cpp
  15. 3
      Source/levels/themes.cpp
  16. 3
      Source/missiles.cpp
  17. 7
      Source/monster.cpp
  18. 3
      Source/mpq/mpq_writer.cpp
  19. 3
      Source/msg.cpp
  20. 7
      Source/multi.cpp
  21. 3
      Source/nthread.cpp
  22. 5
      Source/objects.cpp
  23. 7
      Source/options.cpp
  24. 43
      Source/panels/charpanel.cpp
  25. 3
      Source/panels/spell_list.cpp
  26. 56
      Source/pfile.cpp
  27. 4
      Source/platform/ctr/messagebox.cpp
  28. 51
      Source/player.cpp
  29. 5
      Source/qol/monhealthbar.cpp
  30. 7
      Source/qol/stash.cpp
  31. 5
      Source/stores.cpp
  32. 3
      Source/utils/display.cpp
  33. 17
      Source/utils/file_name_generator.hpp
  34. 3
      Source/utils/format_int.cpp
  35. 3
      Source/utils/log.hpp
  36. 28
      Source/utils/str_cat.cpp
  37. 82
      Source/utils/str_cat.hpp

1
Source/CMakeLists.txt

@ -163,6 +163,7 @@ set(libdevilutionx_SRCS
utils/pcx.cpp
utils/sdl_bilinear_scale.cpp
utils/sdl_thread.cpp
utils/str_cat.cpp
utils/utf8.cpp)
if(IOS)

3
Source/DiabloUI/selgame.cpp

@ -13,6 +13,7 @@
#include "options.h"
#include "storm/storm_net.hpp"
#include "utils/language.h"
#include "utils/str_cat.hpp"
#include "utils/utf8.hpp"
namespace devilution {
@ -254,7 +255,7 @@ void selgame_GameSelection_Focus(int value)
break;
default:
// This should not occure, so no translations is needed
infoString.append(fmt::format("Speed: {}", gameInfo.gameData.nTickRate));
infoString.append(StrCat("Speed: ", gameInfo.gameData.nTickRate));
break;
}
infoString += '\n';

15
Source/DiabloUI/selhero.cpp

@ -14,11 +14,12 @@
#include "DiabloUI/selyesno.h"
#include "control.h"
#include "controls/plrctrls.h"
#include "menu.h"
#include "options.h"
#include "pfile.h"
#include "utils/language.h"
#include "utils/str_cat.hpp"
#include "utils/utf8.hpp"
#include <menu.h>
namespace devilution {
@ -78,12 +79,12 @@ void SelheroFree()
void SelheroSetStats()
{
SELHERO_DIALOG_HERO_IMG->setSprite(UiGetHeroDialogSprite(static_cast<size_t>(selhero_heroInfo.heroclass)));
CopyUtf8(textStats[0], fmt::format("{}", selhero_heroInfo.level), sizeof(textStats[0]));
CopyUtf8(textStats[1], fmt::format("{}", selhero_heroInfo.strength), sizeof(textStats[1]));
CopyUtf8(textStats[2], fmt::format("{}", selhero_heroInfo.magic), sizeof(textStats[2]));
CopyUtf8(textStats[3], fmt::format("{}", selhero_heroInfo.dexterity), sizeof(textStats[3]));
CopyUtf8(textStats[4], fmt::format("{}", selhero_heroInfo.vitality), sizeof(textStats[4]));
CopyUtf8(textStats[5], fmt::format("{}", selhero_heroInfo.saveNumber), sizeof(textStats[5]));
CopyUtf8(textStats[0], StrCat(selhero_heroInfo.level), sizeof(textStats[0]));
CopyUtf8(textStats[1], StrCat(selhero_heroInfo.strength), sizeof(textStats[1]));
CopyUtf8(textStats[2], StrCat(selhero_heroInfo.magic), sizeof(textStats[2]));
CopyUtf8(textStats[3], StrCat(selhero_heroInfo.dexterity), sizeof(textStats[3]));
CopyUtf8(textStats[4], StrCat(selhero_heroInfo.vitality), sizeof(textStats[4]));
CopyUtf8(textStats[5], StrCat(selhero_heroInfo.saveNumber), sizeof(textStats[5]));
}
UiArtTextButton *SELLIST_DIALOG_DELETE_BUTTON;

3
Source/appfat.cpp

@ -13,6 +13,7 @@
#include "storm/storm_net.hpp"
#include "utils/language.h"
#include "utils/sdl_thread.h"
#include "utils/str_cat.hpp"
#include "utils/ui_fwd.h"
namespace devilution {
@ -55,7 +56,7 @@ void app_fatal(string_view str)
#ifdef _DEBUG
void assert_fail(int nLineNo, const char *pszFile, const char *pszFail)
{
app_fatal(fmt::format("assertion failed ({}:{})\n{}", pszFile, nLineNo, pszFail));
app_fatal(StrCat("assertion failed (", pszFile, ":", nLineNo, ")\n", pszFail));
}
#endif

9
Source/control.cpp

@ -46,6 +46,7 @@
#include "utils/language.h"
#include "utils/sdl_geometry.h"
#include "utils/stdcompat/optional.hpp"
#include "utils/str_cat.hpp"
#include "utils/string_or_view.hpp"
#include "utils/utf8.hpp"
@ -528,10 +529,10 @@ void DrawFlaskValues(const Surface &out, Point pos, int currValue, int maxValue)
DrawString(out, text, pos, color | UiFlags::KerningFitSpacing, 0);
};
std::string currText = fmt::format("{:d}", currValue);
std::string currText = StrCat(currValue);
drawStringWithShadow(currText, pos - Displacement { GetLineWidth(currText, GameFont12) + 1, 0 });
drawStringWithShadow("/", pos);
drawStringWithShadow(fmt::format("{:d}", maxValue), pos + Displacement { GetLineWidth("/", GameFont12) + 1, 0 });
drawStringWithShadow(StrCat(maxValue), pos + Displacement { GetLineWidth("/", GameFont12) + 1, 0 });
}
void control_update_life_mana()
@ -1078,9 +1079,9 @@ void DrawGoldSplit(const Surface &out, int amount)
// for the text entered by the player.
DrawString(out, wrapped, { GetPanelPosition(UiPanels::Inventory, { dialogX + 31, 75 }), { 200, 50 } }, UiFlags::ColorWhitegold | UiFlags::AlignCenter, 1, 17);
std::string value = "";
std::string value;
if (amount > 0) {
value = fmt::format("{:d}", amount);
value = StrCat(amount);
}
// Even a ten digit amount of gold only takes up about half a line. There's no need to wrap or clip text here so we
// use the Point form of DrawString.

3
Source/controls/plrctrls.cpp

@ -36,6 +36,7 @@
#include "towners.h"
#include "track.h"
#include "utils/log.hpp"
#include "utils/str_cat.hpp"
#define SPLICONLENGTH 56
@ -1469,7 +1470,7 @@ void LogControlDeviceAndModeChange(ControlTypes newControlDevice, ControlTypes n
constexpr auto DebugChange = [](ControlTypes before, ControlTypes after) -> std::string {
if (before == after)
return std::string { ControlTypeToString(before) };
return fmt::format("{} -> {}", ControlTypeToString(before), ControlTypeToString(after));
return StrCat(ControlTypeToString(before), " -> ", ControlTypeToString(after));
};
LogVerbose("Control: device {}, mode {}", DebugChange(ControlDevice, newControlDevice), DebugChange(ControlMode, newControlMode));
}

125
Source/debug.cpp

@ -9,9 +9,6 @@
#include <fstream>
#include <sstream>
#include <fmt/compile.h>
#include <fmt/format.h>
#include "debug.h"
#include "automap.h"
@ -31,6 +28,7 @@
#include "towners.h"
#include "utils/language.h"
#include "utils/log.hpp"
#include "utils/str_cat.hpp"
namespace devilution {
@ -97,16 +95,11 @@ void PrintDebugMonster(int m)
{
auto &monster = Monsters[m];
EventPlrMsg(fmt::format(
"Monster {:d} = {:s}\nX = {:d}, Y = {:d}\nEnemy = {:d}, HP = {:d}\nMode = {:d}, Var1 = {:d}",
m,
monster.name,
monster.position.tile.x,
monster.position.tile.y,
monster.enemy,
monster.hitPoints,
static_cast<int>(monster.mode),
monster.var1),
EventPlrMsg(StrCat(
"Monster ", m, " = ", monster.name,
"\nX = ", monster.position.tile.x, ", Y = ", monster.position.tile.y,
"\nEnemy = ", monster.enemy, ", HP = ", monster.hitPoints,
"\nMode = ", static_cast<int>(monster.mode), ", Var1 = ", monster.var1),
UiFlags::ColorWhite);
bool bActive = false;
@ -116,7 +109,7 @@ void PrintDebugMonster(int m)
bActive = true;
}
EventPlrMsg(fmt::format("Active List = {:d}, Squelch = {:d}", bActive ? 1 : 0, monster.activeForTicks), UiFlags::ColorWhite);
EventPlrMsg(StrCat("Active List = ", bActive ? 1 : 0, ", Squelch = ", monster.activeForTicks), UiFlags::ColorWhite);
}
void ProcessMessages()
@ -155,15 +148,14 @@ std::string DebugCmdHelp(const string_view parameter)
ret.append(std::string(dbgCmd.text));
}
return ret;
} else {
auto debugCmdIterator = std::find_if(DebugCmdList.begin(), DebugCmdList.end(), [&](const DebugCmdItem &elem) { return elem.text == parameter; });
if (debugCmdIterator == DebugCmdList.end())
return fmt::format("Debug command {} wasn't found", parameter);
auto &dbgCmdItem = *debugCmdIterator;
if (dbgCmdItem.requiredParameter.empty())
return fmt::format("Description: {}\nParameters: No additional parameter needed.", dbgCmdItem.description);
return fmt::format("Description: {}\nParameters: {}", dbgCmdItem.description, dbgCmdItem.requiredParameter);
}
auto debugCmdIterator = std::find_if(DebugCmdList.begin(), DebugCmdList.end(), [&](const DebugCmdItem &elem) { return elem.text == parameter; });
if (debugCmdIterator == DebugCmdList.end())
return StrCat("Debug command ", parameter, " wasn't found");
auto &dbgCmdItem = *debugCmdIterator;
if (dbgCmdItem.requiredParameter.empty())
return StrCat("Description: ", dbgCmdItem.description, "\nParameters: No additional parameter needed.");
return StrCat("Description: ", dbgCmdItem.description, "\nParameters: ", dbgCmdItem.requiredParameter);
}
std::string DebugCmdGiveGoldCheat(const string_view parameter)
@ -211,12 +203,12 @@ std::string DebugCmdWarpToLevel(const string_view parameter)
Player &myPlayer = *MyPlayer;
auto level = atoi(parameter.data());
if (level < 0 || level > (gbIsHellfire ? 24 : 16))
return fmt::format("Level {} is not known. Do you want to write a mod?", level);
return StrCat("Level ", level, " is not known. Do you want to write a mod?");
if (!setlevel && myPlayer.isOnLevel(level))
return fmt::format("I did nothing but fulfilled your wish. You are already at level {}.", level);
return StrCat("I did nothing but fulfilled your wish. You are already at level ", level, ".");
StartNewLvl(MyPlayerId, (level != 21) ? interface_mode::WM_DIABNEXTLVL : interface_mode::WM_DIABTOWNWARP, level);
return fmt::format("Welcome to level {}.", level);
return StrCat("Welcome to level ", level, ".");
}
std::string DebugCmdLoadQuestMap(const string_view parameter)
@ -226,16 +218,16 @@ std::string DebugCmdLoadQuestMap(const string_view parameter)
for (auto &quest : Quests) {
if (quest._qslvl <= 0)
continue;
ret.append(fmt::format(" {} ({})", quest._qslvl, QuestLevelNames[quest._qslvl]));
StrAppend(ret, " ", quest._qslvl, " (", QuestLevelNames[quest._qslvl], ")");
}
return ret;
}
auto level = atoi(parameter.data());
if (level < 1)
return fmt::format("Map id must be 1 or higher", level);
return "Map id must be 1 or higher";
if (setlevel && setlvlnum == level)
return fmt::format("I did nothing but fulfilled your wish. You are already at mapid {}.", level);
return StrCat("I did nothing but fulfilled your wish. You are already at mapid .", level);
for (auto &quest : Quests) {
if (level != quest._qslvl)
@ -249,10 +241,10 @@ std::string DebugCmdLoadQuestMap(const string_view parameter)
setlvltype = quest._qlvltype;
StartNewLvl(MyPlayerId, WM_DIABSETLVL, level);
return fmt::format("Welcome to {}.", QuestLevelNames[level]);
return StrCat("Welcome to ", QuestLevelNames[level], ".");
}
return fmt::format("Mapid {} is not known. Do you want to write a mod?", level);
return StrCat("Mapid ", level, " is not known. Do you want to write a mod?");
}
std::string DebugCmdLoadMap(const string_view parameter)
@ -266,7 +258,7 @@ std::string DebugCmdLoadMap(const string_view parameter)
for (std::string tmp; std::getline(paramsStream, tmp, ' ');) {
switch (count) {
case 0:
TestMapPath = fmt::format("{:s}.dun", tmp);
TestMapPath = StrCat(tmp, ".dun");
break;
case 1:
mapType = atoi(tmp.c_str());
@ -308,7 +300,7 @@ std::string ExportDun(const string_view parameter)
{
std::ofstream dunFile;
std::string levelName = fmt::format("{}-{}.dun", currlevel, glSeedTbl[currlevel]);
std::string levelName = StrCat(currlevel, "-", glSeedTbl[currlevel], ".dun");
dunFile.open(levelName, std::ios::out | std::ios::app | std::ios::binary);
@ -369,7 +361,7 @@ std::string ExportDun(const string_view parameter)
}
dunFile.close();
return fmt::format("{} saved. Happy mapping!", levelName);
return StrCat(levelName, " saved. Happy mapping!");
}
std::unordered_map<string_view, _talker_id> TownerShortNameToTownerId = {
@ -405,7 +397,7 @@ std::string DebugCmdVisitTowner(const string_view parameter)
auto it = TownerShortNameToTownerId.find(parameter);
if (it == TownerShortNameToTownerId.end())
return fmt::format("{} is unknown. Perhaps he is a ninja?", parameter);
return StrCat(parameter, " is unknown. Perhaps he is a ninja?");
for (auto &towner : Towners) {
if (towner._ttype != it->second)
@ -420,10 +412,10 @@ std::string DebugCmdVisitTowner(const string_view parameter)
towner.position.y,
1);
return fmt::format("Say hello to {} from me.", parameter);
return StrCat("Say hello to ", parameter, " from me.");
}
return fmt::format("Couldn't find {}.", parameter);
return StrCat("Couldn't find ", parameter, ".");
}
std::string DebugCmdResetLevel(const string_view parameter)
@ -436,7 +428,7 @@ std::string DebugCmdResetLevel(const string_view parameter)
return "What level do you want to visit?";
auto level = atoi(singleParameter.c_str());
if (level < 0 || level > (gbIsHellfire ? 24 : 16))
return fmt::format("Level {} is not known. Do you want to write an extension mod?", level);
return StrCat("Level ", level, " is not known. Do you want to write an extension mod?");
myPlayer._pLvlVisited[level] = false;
if (std::getline(paramsStream, singleParameter, ' ')) {
@ -445,8 +437,8 @@ std::string DebugCmdResetLevel(const string_view parameter)
}
if (myPlayer.isOnLevel(level))
return fmt::format("Level {} can't be cleaned, cause you still occupy it!", level);
return fmt::format("Level {} was restored and looks fabulous.", level);
return StrCat("Level ", level, " can't be cleaned, cause you still occupy it!");
return StrCat("Level ", level, " was restored and looks fabulous.");
}
std::string DebugCmdGodMode(const string_view parameter)
@ -498,7 +490,7 @@ std::string DebugCmdQuest(const string_view parameter)
for (auto &quest : Quests) {
if (IsNoneOf(quest._qactive, QUEST_NOTAVAIL, QUEST_INIT))
continue;
ret.append(fmt::format(", {} ({})", quest._qidx, QuestsData[quest._qidx]._qlstr));
StrAppend(ret, ", ", quest._qidx, " (", QuestsData[quest._qidx]._qlstr, ")");
}
return ret;
}
@ -518,16 +510,16 @@ std::string DebugCmdQuest(const string_view parameter)
int questId = atoi(parameter.data());
if (questId >= MAXQUESTS)
return fmt::format("Quest {} is not known. Do you want to write a mod?", questId);
return StrCat("Quest ", questId, " is not known. Do you want to write a mod?");
auto &quest = Quests[questId];
if (IsNoneOf(quest._qactive, QUEST_NOTAVAIL, QUEST_INIT))
return fmt::format("{} was already given.", QuestsData[questId]._qlstr);
return StrCat(QuestsData[questId]._qlstr, " was already given.");
quest._qactive = QUEST_ACTIVE;
quest._qlog = true;
return fmt::format("{} enabled.", QuestsData[questId]._qlstr);
return StrCat(QuestsData[questId]._qlstr, " enabled.");
}
std::string DebugCmdLevelUp(const string_view parameter)
@ -572,14 +564,14 @@ std::string DebugCmdChangeHealth(const string_view parameter)
change = atoi(parameter.data());
if (change == 0)
return fmt::format("Health hasn't changed.");
return "Health hasn't changed.";
int newHealth = myPlayer._pHitPoints + (change * 64);
SetPlayerHitPoints(myPlayer, newHealth);
if (newHealth <= 0)
SyncPlrKill(MyPlayerId, 0);
return fmt::format("Health has changed.");
return "Health has changed.";
}
std::string DebugCmdChangeMana(const string_view parameter)
@ -591,14 +583,14 @@ std::string DebugCmdChangeMana(const string_view parameter)
change = atoi(parameter.data());
if (change == 0)
return fmt::format("Mana hasn't changed.");
return "Mana hasn't changed.";
int newMana = myPlayer._pMana + (change * 64);
myPlayer._pMana = newMana;
myPlayer._pManaBase = myPlayer._pMana + myPlayer._pMaxManaBase - myPlayer._pMaxMana;
drawmanaflag = true;
return fmt::format("Mana has changed.");
return "Mana has changed.";
}
std::string DebugCmdGenerateUniqueItem(const string_view parameter)
@ -659,7 +651,7 @@ std::string DebugCmdShowGrid(const string_view parameter)
std::string DebugCmdLevelSeed(const string_view parameter)
{
return fmt::format("Seedinfo for level {}\nseed: {}\nMid1: {}\nMid2: {}\nMid3: {}\nEnd: {}", currlevel, glSeedTbl[currlevel], glMid1Seed[currlevel], glMid2Seed[currlevel], glMid3Seed[currlevel], glEndSeed[currlevel]);
return StrCat("Seedinfo for level ", currlevel, "\nseed: ", glSeedTbl[currlevel], "\nMid1: ", glMid1Seed[currlevel], "\nMid2: ", glMid2Seed[currlevel], "\nMid3: ", glMid3Seed[currlevel], "\nEnd: ", glEndSeed[currlevel]);
}
std::string DebugCmdSpawnUniqueMonster(const string_view parameter)
@ -732,7 +724,7 @@ std::string DebugCmdSpawnUniqueMonster(const string_view parameter)
Monster *monster = AddMonster(pos, myPlayer._pdir, id, true);
if (monster == nullptr)
return fmt::format("I could only summon {} Monsters. The rest strike for shorter working hours.", spawnedMonster);
return StrCat("I could only summon ", spawnedMonster, " Monsters. The rest strike for shorter working hours.");
PrepareUniqueMonst(*monster, uniqueIndex, 0, 0, UniqueMonstersData[uniqueIndex]);
ActiveMonsterCount--;
monster->corpseId = 1;
@ -745,7 +737,7 @@ std::string DebugCmdSpawnUniqueMonster(const string_view parameter)
});
if (!ret)
ret = fmt::format("I could only summon {} Monsters. The rest strike for shorter working hours.", spawnedMonster);
ret = StrCat("I could only summon ", spawnedMonster, " Monsters. The rest strike for shorter working hours.");
return *ret;
}
@ -817,7 +809,7 @@ std::string DebugCmdSpawnMonster(const string_view parameter)
return {};
if (AddMonster(pos, myPlayer._pdir, id, true) == nullptr)
return fmt::format("I could only summon {} Monsters. The rest strike for shorter working hours.", spawnedMonster);
return StrCat("I could only summon ", spawnedMonster, " Monsters. The rest strike for shorter working hours.");
spawnedMonster += 1;
if (spawnedMonster >= count)
@ -827,7 +819,7 @@ std::string DebugCmdSpawnMonster(const string_view parameter)
});
if (!ret)
ret = fmt::format("I could only summon {} Monsters. The rest strike for shorter working hours.", spawnedMonster);
ret = StrCat("I could only summon ", spawnedMonster, " Monsters. The rest strike for shorter working hours.");
return *ret;
}
@ -913,9 +905,9 @@ std::string DebugCmdItemInfo(const string_view parameter)
pItem = &Items[pcursitem];
}
if (pItem != nullptr) {
return fmt::format("Name: {}\nIDidx: {}\nSeed: {}\nCreateInfo: {}", pItem->_iIName, pItem->IDidx, pItem->_iSeed, pItem->_iCreateInfo);
return StrCat("Name: ", pItem->_iIName, "\nIDidx: ", pItem->IDidx, "\nSeed: ", pItem->_iSeed, "\nCreateInfo: ", pItem->_iCreateInfo);
}
return fmt::format("Numitems: {}", ActiveItemCount);
return StrCat("Numitems: ", ActiveItemCount);
}
std::string DebugCmdQuestInfo(const string_view parameter)
@ -925,7 +917,7 @@ std::string DebugCmdQuestInfo(const string_view parameter)
for (auto &quest : Quests) {
if (IsNoneOf(quest._qactive, QUEST_NOTAVAIL, QUEST_INIT))
continue;
ret.append(fmt::format(" {} ({})", quest._qidx, QuestsData[quest._qidx]._qlstr));
StrAppend(ret, ", ", quest._qidx, " (", QuestsData[quest._qidx]._qlstr, ")");
}
return ret;
}
@ -933,9 +925,9 @@ std::string DebugCmdQuestInfo(const string_view parameter)
int questId = atoi(parameter.data());
if (questId >= MAXQUESTS)
return fmt::format("Quest {} is not known. Do you want to write a mod?", questId);
return StrCat("Quest ", questId, " is not known. Do you want to write a mod?");
auto &quest = Quests[questId];
return fmt::format("\nQuest: {}\nActive: {} Var1: {} Var2: {}", QuestsData[quest._qidx]._qlstr, quest._qactive, quest._qvar1, quest._qvar2);
return StrCat("\nQuest: ", QuestsData[quest._qidx]._qlstr, "\nActive: ", quest._qactive, " Var1: ", quest._qvar1, " Var2: ", quest._qvar2);
}
std::string DebugCmdPlayerInfo(const string_view parameter)
@ -948,12 +940,11 @@ std::string DebugCmdPlayerInfo(const string_view parameter)
return "Player is not active";
const Point target = player.GetTargetPosition();
return fmt::format("Plr {} is {}\nLvl: {} Changing: {}\nTile.x: {} Tile.y: {} Target.x: {} Target.y: {}\nMode: {} destAction: {} walkpath[0]: {}\nInvincible:{} HitPoints:{}",
playerId, player._pName,
player.plrlevel, player._pLvlChanging,
player.position.tile.x, player.position.tile.y, target.x, target.y,
player._pmode, player.destAction, player.walkpath[0],
player._pInvincible ? 1 : 0, player._pHitPoints);
return StrCat("Plr ", playerId, " is ", player._pName,
"\nLvl: ", player.plrlevel, " Changing: ", player._pLvlChanging,
"\nTile.x: ", player.position.tile.x, " Tile.y: ", player.position.tile.y, " Target.x: ", target.x, " Target.y: ", target.y,
"\nMode: ", player._pmode, " destAction: ", player.destAction, " walkpath[0]: ", player.walkpath[0],
"\nInvincible:", player._pInvincible ? 1 : 0, " HitPoints:", player._pHitPoints);
}
std::string DebugCmdToggleFPS(const string_view parameter)
@ -1032,7 +1023,7 @@ void NextDebugMonster()
if (DebugMonsterId == MaxMonsters)
DebugMonsterId = 0;
EventPlrMsg(fmt::format("Current debug monster = {:d}", DebugMonsterId), UiFlags::ColorWhite);
EventPlrMsg(StrCat("Current debug monster = ", DebugMonsterId), UiFlags::ColorWhite);
}
void SetDebugLevelSeedInfos(uint32_t mid1Seed, uint32_t mid2Seed, uint32_t mid3Seed, uint32_t endSeed)
@ -1084,12 +1075,12 @@ bool GetDebugGridText(Point dungeonCoords, char *debugGridTextBuffer)
Point megaCoords = dungeonCoords.worldToMega();
switch (SelectedDebugGridTextItem) {
case DebugGridTextItem::coords:
*fmt::format_to(debugGridTextBuffer, FMT_COMPILE("{}:{}"), dungeonCoords.x, dungeonCoords.y) = '\0';
*BufCopy(debugGridTextBuffer, dungeonCoords.x, ":", dungeonCoords.y) = '\0';
return true;
case DebugGridTextItem::cursorcoords:
if (dungeonCoords != cursPosition)
return false;
*fmt::format_to(debugGridTextBuffer, FMT_COMPILE("{}:{}"), dungeonCoords.x, dungeonCoords.y) = '\0';
*BufCopy(debugGridTextBuffer, dungeonCoords.x, ":", dungeonCoords.y) = '\0';
return true;
case DebugGridTextItem::objectindex: {
info = 0;
@ -1158,7 +1149,7 @@ bool GetDebugGridText(Point dungeonCoords, char *debugGridTextBuffer)
}
if (info == 0)
return false;
*fmt::format_to(debugGridTextBuffer, FMT_COMPILE("{}"), info) = '\0';
*BufCopy(debugGridTextBuffer, info) = '\0';
return true;
}

5
Source/discord/discord.cpp

@ -19,6 +19,7 @@
#include "panels/charpanel.hpp"
#include "player.h"
#include "utils/language.h"
#include "utils/str_cat.hpp"
namespace devilution {
namespace discord_manager {
@ -92,7 +93,7 @@ std::string GetCharacterString()
std::string GetDetailString()
{
return fmt::format("{} - {}", GetCharacterString(), GetLocationString());
return StrCat(GetCharacterString(), " - ", GetLocationString());
}
std::string GetStateString()
@ -104,7 +105,7 @@ std::string GetStateString()
std::string GetTooltipString()
{
return fmt::format("{} - {}", MyPlayer->_pName, GetCharacterString());
return StrCat(MyPlayer->_pName, " - ", GetCharacterString());
}
std::string GetPlayerAssetString()

5
Source/effects.cpp

@ -5,14 +5,13 @@
*/
#include "effects.h"
#include <fmt/compile.h>
#include "engine/random.hpp"
#include "engine/sound.h"
#include "engine/sound_defs.hpp"
#include "init.h"
#include "player.h"
#include "utils/stdcompat/algorithm.hpp"
#include "utils/str_cat.hpp"
namespace devilution {
@ -1222,7 +1221,7 @@ void InitMonsterSND(int monst)
if (MonstSndChar[i] != 's' || MonstersData[mtype].snd_special) {
for (int j = 0; j < 2; j++) {
char path[MAX_PATH];
*fmt::format_to(path, FMT_COMPILE("{}{}{}.WAV"), MonstersData[mtype].sndfile, MonstSndChar[i], j + 1) = '\0';
*BufCopy(path, MonstersData[mtype].sndfile, string_view(&MonstSndChar[i], 1), j + 1, ".WAV") = '\0';
LevelMonsterTypes[monst].sounds[i][j] = sound_file_load(path);
}
}

7
Source/engine/load_file.hpp

@ -12,6 +12,7 @@
#include "engine/assets.hpp"
#include "utils/static_vector.hpp"
#include "utils/stdcompat/cstddef.hpp"
#include "utils/str_cat.hpp"
namespace devilution {
@ -22,7 +23,7 @@ public:
handle_ = OpenAsset(path);
if (handle_ == nullptr) {
if (!gbQuietMode) {
app_fatal(fmt::format("Failed to open file:\n{}\n\n{}", path, SDL_GetError()));
app_fatal(StrCat("Failed to open file:\n", path, "\n\n", SDL_GetError()));
}
}
}
@ -60,7 +61,7 @@ void LoadFileInMem(const char *path, T *data)
return;
const std::size_t fileLen = file.Size();
if ((fileLen % sizeof(T)) != 0)
app_fatal(fmt::format("File size does not align with type\n{}", path));
app_fatal(StrCat("File size does not align with type\n", path));
file.Read(reinterpret_cast<byte *>(data), fileLen);
}
@ -93,7 +94,7 @@ std::unique_ptr<T[]> LoadFileInMem(const char *path, std::size_t *numRead = null
return nullptr;
const std::size_t fileLen = file.Size();
if ((fileLen % sizeof(T)) != 0)
app_fatal(fmt::format("File size does not align with type\n{}", path));
app_fatal(StrCat("File size does not align with type\n", path));
if (numRead != nullptr)
*numRead = fileLen / sizeof(T);

5
Source/engine/render/scrollrt.cpp

@ -5,8 +5,6 @@
*/
#include "engine/render/scrollrt.h"
#include <fmt/compile.h>
#include "DiabloUI/ui_flags.hpp"
#include "automap.h"
#include "controls/plrctrls.h"
@ -43,6 +41,7 @@
#include "utils/display.h"
#include "utils/endian.hpp"
#include "utils/log.hpp"
#include "utils/str_cat.hpp"
#ifdef _DEBUG
#include "debug.h"
@ -1326,7 +1325,7 @@ void DrawFPS(const Surface &out)
framesSinceLastUpdate = 0;
static char buf[12] {};
const char *end = fmt::format_to_n(buf, sizeof(buf), FMT_COMPILE("{} FPS"), framerate).out;
const char *end = BufCopy(buf, framerate, " FPS");
formatted = { buf, static_cast<string_view::size_type>(end - buf) };
};
DrawString(out, formatted, Point { 8, 68 }, UiFlags::ColorRed);

3
Source/engine/sound.cpp

@ -21,6 +21,7 @@
#include "utils/stdcompat/algorithm.hpp"
#include "utils/stdcompat/optional.hpp"
#include "utils/stdcompat/shared_ptr_array.hpp"
#include "utils/str_cat.hpp"
#include "utils/stubs.h"
namespace devilution {
@ -76,7 +77,7 @@ bool LoadAudioFile(const char *path, bool stream, bool errorDialog, SoundSample
auto waveFile = MakeArraySharedPtr<std::uint8_t>(dwBytes);
if (SDL_RWread(file, waveFile.get(), dwBytes, 1) == 0) {
if (errorDialog)
ErrDlg("Failed to read file", fmt::format("{}: {}", path, SDL_GetError()), __FILE__, __LINE__);
ErrDlg("Failed to read file", StrCat(path, ": ", SDL_GetError()), __FILE__, __LINE__);
return false;
}
int error = result.SetChunk(waveFile, dwBytes, isMp3);

5
Source/inv.cpp

@ -30,6 +30,7 @@
#include "utils/language.h"
#include "utils/sdl_geometry.h"
#include "utils/stdcompat/optional.hpp"
#include "utils/str_cat.hpp"
#include "utils/utf8.hpp"
namespace devilution {
@ -1219,7 +1220,7 @@ void DrawInvBelt(const Surface &out)
if (AllItemsList[myPlayer.SpdList[i].IDidx].iUsable
&& myPlayer.SpdList[i]._itype != ItemType::Gold) {
DrawString(out, fmt::format("{:d}", i + 1), { position - Displacement { 0, 12 }, InventorySlotSizeInPixels }, UiFlags::ColorWhite | UiFlags::AlignRight);
DrawString(out, StrCat(i + 1), { position - Displacement { 0, 12 }, InventorySlotSizeInPixels }, UiFlags::ColorWhite | UiFlags::AlignRight);
}
}
}
@ -1353,7 +1354,7 @@ bool AutoPlaceItemInInventory(Player &player, const Item &item, bool persistItem
return false;
}
app_fatal(fmt::format("Unknown item size: {}x{}", itemSize.width, itemSize.height));
app_fatal(StrCat("Unknown item size: ", itemSize.width, "x", itemSize.height));
}
bool AutoPlaceItemInInventorySlot(Player &player, int slotIndex, const Item &item, bool persistItem)

15
Source/items.cpp

@ -42,6 +42,7 @@
#include "utils/language.h"
#include "utils/math.h"
#include "utils/stdcompat/algorithm.hpp"
#include "utils/str_cat.hpp"
#include "utils/utf8.hpp"
namespace devilution {
@ -2297,7 +2298,7 @@ void InitItemGFX()
int itemTypes = gbIsHellfire ? ITEMTYPES : 35;
for (int i = 0; i < itemTypes; i++) {
*fmt::format_to(arglist, FMT_COMPILE(R"(Items\{}.CEL)"), ItemDropNames[i]) = '\0';
*BufCopy(arglist, "Items\\", ItemDropNames[i], ".CEL") = '\0';
itemanims[i] = LoadCel(arglist, ItemAnimWidth);
}
memset(UniqueItemFlags, 0, sizeof(UniqueItemFlags));
@ -4461,10 +4462,10 @@ std::string DebugSpawnItem(std::string itemName)
std::uniform_int_distribution<int32_t> dist(0, INT_MAX);
SetRndSeed(dist(BetterRng));
if (SDL_GetTicks() - begin > max_time)
return fmt::format("Item not found in {:d} seconds!", max_time / 1000);
return StrCat("Item not found in ", max_time / 1000, " seconds!");
if (i > max_iter)
return fmt::format("Item not found in {:d} tries!", max_iter);
return StrCat("Item not found in ", max_iter, " tries!");
fake_m.level = dist(BetterRng) % CF_LEVEL + 1;
@ -4487,7 +4488,7 @@ std::string DebugSpawnItem(std::string itemName)
item._iIdentified = true;
NetSendCmdPItem(false, CMD_DROPITEM, item.position, item);
return fmt::format("Item generated successfully - iterations: {:d}", i);
return StrCat("Item generated successfully - iterations: ", i);
}
std::string DebugSpawnUniqueItem(std::string itemName)
@ -4535,10 +4536,10 @@ std::string DebugSpawnUniqueItem(std::string itemName)
int i = 0;
for (uint32_t begin = SDL_GetTicks();; i++) {
if (SDL_GetTicks() - begin > max_time)
return fmt::format("Item not found in {:d} seconds!", max_time / 1000);
return StrCat("Item not found in ", max_time / 1000, " seconds!");
if (i > max_iter)
return fmt::format("Item not found in {:d} tries!", max_iter);
return StrCat("Item not found in ", max_iter, " tries!");
Point bkp = item.position;
item = {};
@ -4564,7 +4565,7 @@ std::string DebugSpawnUniqueItem(std::string itemName)
item._iIdentified = true;
NetSendCmdPItem(false, CMD_DROPITEM, item.position, item);
return fmt::format("Item generated successfully - iterations: {:d}", i);
return StrCat("Item generated successfully - iterations: ", i);
}
#endif

3
Source/levels/themes.cpp

@ -15,6 +15,7 @@
#include "monster.h"
#include "objects.h"
#include "quests.h"
#include "utils/str_cat.hpp"
namespace devilution {
@ -1008,7 +1009,7 @@ void CreateThemeRooms()
Theme_WeaponRack(i);
break;
case THEME_NONE:
app_fatal(fmt::format("Unknown theme type: {}", static_cast<int>(themes[i].ttype)));
app_fatal(StrCat("Unknown theme type: ", static_cast<int>(themes[i].ttype)));
}
}
ApplyObjectLighting = false;

3
Source/missiles.cpp

@ -23,6 +23,7 @@
#include "lighting.h"
#include "monster.h"
#include "spells.h"
#include "utils/str_cat.hpp"
namespace devilution {
@ -2668,7 +2669,7 @@ void MI_LArrow(Missile &missile)
eRst = MISR_FIRE;
break;
default:
app_fatal(fmt::format("wrong missile ID {}", static_cast<int>(missile._mitype)));
app_fatal(StrCat("wrong missile ID ", static_cast<int>(missile._mitype)));
break;
}
SetMissAnim(missile, eAnim);

7
Source/monster.cpp

@ -37,6 +37,7 @@
#include "utils/file_name_generator.hpp"
#include "utils/language.h"
#include "utils/stdcompat/string_view.hpp"
#include "utils/str_cat.hpp"
#include "utils/utf8.hpp"
#ifdef _DEBUG
@ -1614,7 +1615,7 @@ void MonsterTalk(Monster &monster)
monster.flags |= MFLAG_QUEST_COMPLETE;
}
if (Quests[Q_LTBANNER]._qvar1 < 2) {
app_fatal(fmt::format("SS Talk = {}, Flags = {}", monster.talkMsg, monster.flags));
app_fatal(StrCat("SS Talk = ", monster.talkMsg, ", Flags = ", monster.flags));
}
}
if (monster.uniqType - 1 == UMT_LACHDAN) {
@ -3282,7 +3283,7 @@ string_view GetMonsterTypeText(const MonsterData &monsterData)
return _("Undead");
}
app_fatal(fmt::format("Unknown mMonstClass {}", static_cast<int>(monsterData.mMonstClass)));
app_fatal(StrCat("Unknown mMonstClass ", static_cast<int>(monsterData.mMonstClass)));
}
void ActivateSpawn(Monster &monster, Point position, Direction dir)
@ -3421,7 +3422,7 @@ bool UpdateModeStance(int monsterId)
void InitTRNForUniqueMonster(Monster &monster)
{
char filestr[64];
*fmt::format_to(filestr, FMT_COMPILE(R"(Monsters\Monsters\{}.TRN)"), UniqueMonstersData[monster.uniqType - 1].mTrnName) = '\0';
*BufCopy(filestr, R"(Monsters\Monsters\)", UniqueMonstersData[monster.uniqType - 1].mTrnName, ".TRN") = '\0';
monster.uniqueMonsterTRN = LoadFileInMem<uint8_t>(filestr);
}

3
Source/mpq/mpq_writer.cpp

@ -15,6 +15,7 @@
#include "utils/file_util.h"
#include "utils/language.h"
#include "utils/log.hpp"
#include "utils/str_cat.hpp"
namespace devilution {
@ -336,7 +337,7 @@ MpqBlockEntry *MpqWriter::AddFile(const char *filename, MpqBlockEntry *block, ui
uint32_t h2 = Hash(filename, 1);
uint32_t h3 = Hash(filename, 2);
if (GetHashIndex(h1, h2, h3) != HashEntryNotFound)
app_fatal(fmt::format("Hash collision between \"{}\" and existing file\n", filename));
app_fatal(StrCat("Hash collision between \"", filename, "\" and existing file\n"));
unsigned int hIdx = h1 & 0x7FF;
bool hasSpace = false;

3
Source/msg.cpp

@ -36,6 +36,7 @@
#include "tmsg.h"
#include "towners.h"
#include "utils/language.h"
#include "utils/str_cat.hpp"
#include "utils/utf8.hpp"
namespace devilution {
@ -446,7 +447,7 @@ void DeltaImportData(_cmd_id cmd, DWORD recvOffset)
src += DeltaImportObject(src, deltaLevel.object);
DeltaImportMonster(src, deltaLevel.monster);
} else {
app_fatal(fmt::format("Unkown network message type: {}", cmd));
app_fatal(StrCat("Unkown network message type: ", cmd));
}
sgbDeltaChunks++;

7
Source/multi.cpp

@ -28,6 +28,7 @@
#include "utils/language.h"
#include "utils/stdcompat/cstddef.hpp"
#include "utils/stdcompat/string_view.hpp"
#include "utils/str_cat.hpp"
namespace devilution {
@ -372,7 +373,7 @@ void HandleEvents(_SNETEVENT *pEvt)
case EVENT_TYPE_PLAYER_CREATE_GAME: {
auto *gameData = (GameData *)pEvt->data;
if (gameData->size != sizeof(GameData))
app_fatal(fmt::format("Invalid size of game data: {}", gameData->size));
app_fatal(StrCat("Invalid size of game data: ", gameData->size));
sgGameInitInfo = *gameData;
sgbPlayerTurnBitTbl[pEvt->playerid] = true;
break;
@ -405,7 +406,7 @@ void EventHandler(bool add)
for (auto eventType : EventTypes) {
if (add) {
if (!SNetRegisterEventHandler(eventType, HandleEvents)) {
app_fatal(fmt::format("SNetRegisterEventHandler:\n{}", SDL_GetError()));
app_fatal(StrCat("SNetRegisterEventHandler:\n", SDL_GetError()));
}
} else {
SNetUnregisterEventHandler(eventType);
@ -421,7 +422,7 @@ bool InitSingle(GameData *gameData)
int unused = 0;
if (!SNetCreateGame("local", "local", (char *)&sgGameInitInfo, sizeof(sgGameInitInfo), &unused)) {
app_fatal(fmt::format("SNetCreateGame1:\n{}", SDL_GetError()));
app_fatal(StrCat("SNetCreateGame1:\n", SDL_GetError()));
}
MyPlayerId = 0;

3
Source/nthread.cpp

@ -13,6 +13,7 @@
#include "storm/storm_net.hpp"
#include "utils/sdl_mutex.h"
#include "utils/sdl_thread.h"
#include "utils/str_cat.hpp"
namespace devilution {
@ -70,7 +71,7 @@ void nthread_terminate_game(const char *pszFcn)
return;
}
if (sErr != STORM_ERROR_GAME_TERMINATED && sErr != STORM_ERROR_NOT_IN_GAME) {
app_fatal(fmt::format("{}:\n{}", pszFcn, SDL_GetError()));
app_fatal(StrCat(pszFcn, ":\n", pszFcn));
}
gbGameDestroyed = true;

5
Source/objects.cpp

@ -7,7 +7,7 @@
#include <climits>
#include <cstdint>
#include <fmt/compile.h>
#include <fmt/core.h>
#include "DiabloUI/ui_flags.hpp"
#include "automap.h"
@ -36,6 +36,7 @@
#include "track.h"
#include "utils/language.h"
#include "utils/log.hpp"
#include "utils/str_cat.hpp"
#include "utils/utf8.hpp"
namespace devilution {
@ -4087,7 +4088,7 @@ void LoadLevelObjects(bool filesLoaded[65])
ObjFileList[numobjfiles] = static_cast<object_graphic_id>(i);
char filestr[32];
*fmt::format_to(filestr, FMT_COMPILE(R"(Objects\{}.CEL)"), ObjMasterLoadList[i]) = '\0';
*BufCopy(filestr, "Objects\\", ObjMasterLoadList[i], ".CEL") = '\0';
pObjCels[numobjfiles] = LoadFileInMem(filestr);
numobjfiles++;
}

7
Source/options.cpp

@ -28,6 +28,7 @@
#include "utils/log.hpp"
#include "utils/paths.h"
#include "utils/stdcompat/algorithm.hpp"
#include "utils/str_cat.hpp"
#include "utils/utf8.hpp"
namespace devilution {
@ -515,7 +516,7 @@ string_view OptionEntryIntBase::GetListDescription(size_t index) const
{
if (entryNames.empty()) {
for (auto value : entryValues) {
entryNames.push_back(fmt::format("{}", value));
entryNames.push_back(StrCat(value));
}
}
return entryNames[index].data();
@ -724,7 +725,7 @@ void OptionEntryResolution::CheckResolutionsAreInitialized() const
sizes.erase(std::unique(sizes.begin(), sizes.end()), sizes.end());
for (auto &size : sizes) {
resolutions.emplace_back(size, fmt::format("{}x{}", size.width, size.height));
resolutions.emplace_back(size, StrCat(size.width, "x", size.height));
}
}
@ -1221,7 +1222,7 @@ KeymapperOptions::KeymapperOptions()
keyIDToKeyName.emplace(c, std::string(1, c));
}
for (int i = 0; i < 12; ++i) {
keyIDToKeyName.emplace(DVL_VK_F1 + i, fmt::format("F{}", i + 1));
keyIDToKeyName.emplace(DVL_VK_F1 + i, StrCat("F", i + 1));
}
keyIDToKeyName.emplace(DVL_VK_LMENU, "LALT");

43
Source/panels/charpanel.cpp

@ -14,6 +14,7 @@
#include "utils/display.h"
#include "utils/format_int.hpp"
#include "utils/language.h"
#include "utils/str_cat.hpp"
namespace devilution {
@ -108,7 +109,7 @@ StyledText GetResistInfo(int8_t resist)
else if (resist >= MaxResistance)
style = UiFlags::ColorWhitegold;
return { style, fmt::format("{:d}%", resist) };
return { style, StrCat(resist, "%") };
}
constexpr int LeftColumnLabelX = 88;
@ -129,11 +130,11 @@ PanelEntry panelEntries[] = {
[]() { return StyledText { UiFlags::ColorWhite, std::string(_(ClassStrTbl[static_cast<std::size_t>(MyPlayer->_pClass)])) }; } },
{ N_("Level"), { 57, 52 }, 57, 45,
[]() { return StyledText { UiFlags::ColorWhite, fmt::format("{:d}", MyPlayer->_pLevel) }; } },
[]() { return StyledText { UiFlags::ColorWhite, StrCat(MyPlayer->_pLevel) }; } },
{ N_("Experience"), { TopRightLabelX, 52 }, 99, 91,
[]() {
int spacing = ((MyPlayer->_pExperience >= 1000000000) ? 0 : 1);
return StyledText { UiFlags::ColorWhite, fmt::format("{:s}", FormatInteger(MyPlayer->_pExperience)), spacing };
return StyledText { UiFlags::ColorWhite, FormatInteger(MyPlayer->_pExperience), spacing };
} },
{ N_("Next level"), { TopRightLabelX, 80 }, 99, 198,
[]() {
@ -141,54 +142,54 @@ PanelEntry panelEntries[] = {
return StyledText { UiFlags::ColorWhitegold, std::string(_("None")) };
}
int spacing = ((MyPlayer->_pNextExper >= 1000000000) ? 0 : 1);
return StyledText { UiFlags::ColorWhite, fmt::format("{:s}", FormatInteger(MyPlayer->_pNextExper)), spacing };
return StyledText { UiFlags::ColorWhite, FormatInteger(MyPlayer->_pNextExper), spacing };
} },
{ N_("Base"), { LeftColumnLabelX, /* set dynamically */ 0 }, 0, 44 },
{ N_("Now"), { 135, /* set dynamically */ 0 }, 0, 44 },
{ N_("Strength"), { LeftColumnLabelX, 135 }, 45, LeftColumnLabelWidth,
[]() { return StyledText { GetBaseStatColor(CharacterAttribute::Strength), fmt::format("{:d}", MyPlayer->_pBaseStr) }; } },
[]() { return StyledText { GetBaseStatColor(CharacterAttribute::Strength), StrCat(MyPlayer->_pBaseStr) }; } },
{ "", { 135, 135 }, 45, 0,
[]() { return StyledText { GetCurrentStatColor(CharacterAttribute::Strength), fmt::format("{:d}", MyPlayer->_pStrength) }; } },
[]() { return StyledText { GetCurrentStatColor(CharacterAttribute::Strength), StrCat(MyPlayer->_pStrength) }; } },
{ N_("Magic"), { LeftColumnLabelX, 163 }, 45, LeftColumnLabelWidth,
[]() { return StyledText { GetBaseStatColor(CharacterAttribute::Magic), fmt::format("{:d}", MyPlayer->_pBaseMag) }; } },
[]() { return StyledText { GetBaseStatColor(CharacterAttribute::Magic), StrCat(MyPlayer->_pBaseMag) }; } },
{ "", { 135, 163 }, 45, 0,
[]() { return StyledText { GetCurrentStatColor(CharacterAttribute::Magic), fmt::format("{:d}", MyPlayer->_pMagic) }; } },
{ N_("Dexterity"), { LeftColumnLabelX, 191 }, 45, LeftColumnLabelWidth, []() { return StyledText { GetBaseStatColor(CharacterAttribute::Dexterity), fmt::format("{:d}", MyPlayer->_pBaseDex) }; } },
[]() { return StyledText { GetCurrentStatColor(CharacterAttribute::Magic), StrCat(MyPlayer->_pMagic) }; } },
{ N_("Dexterity"), { LeftColumnLabelX, 191 }, 45, LeftColumnLabelWidth, []() { return StyledText { GetBaseStatColor(CharacterAttribute::Dexterity), StrCat(MyPlayer->_pBaseDex) }; } },
{ "", { 135, 191 }, 45, 0,
[]() { return StyledText { GetCurrentStatColor(CharacterAttribute::Dexterity), fmt::format("{:d}", MyPlayer->_pDexterity) }; } },
{ N_("Vitality"), { LeftColumnLabelX, 219 }, 45, LeftColumnLabelWidth, []() { return StyledText { GetBaseStatColor(CharacterAttribute::Vitality), fmt::format("{:d}", MyPlayer->_pBaseVit) }; } },
[]() { return StyledText { GetCurrentStatColor(CharacterAttribute::Dexterity), StrCat(MyPlayer->_pDexterity) }; } },
{ N_("Vitality"), { LeftColumnLabelX, 219 }, 45, LeftColumnLabelWidth, []() { return StyledText { GetBaseStatColor(CharacterAttribute::Vitality), StrCat(MyPlayer->_pBaseVit) }; } },
{ "", { 135, 219 }, 45, 0,
[]() { return StyledText { GetCurrentStatColor(CharacterAttribute::Vitality), fmt::format("{:d}", MyPlayer->_pVitality) }; } },
[]() { return StyledText { GetCurrentStatColor(CharacterAttribute::Vitality), StrCat(MyPlayer->_pVitality) }; } },
{ N_("Points to distribute"), { LeftColumnLabelX, 248 }, 45, LeftColumnLabelWidth,
[]() {
MyPlayer->_pStatPts = std::min(CalcStatDiff(*MyPlayer), MyPlayer->_pStatPts);
return StyledText { UiFlags::ColorRed, (MyPlayer->_pStatPts > 0 ? fmt::format("{:d}", MyPlayer->_pStatPts) : "") };
return StyledText { UiFlags::ColorRed, (MyPlayer->_pStatPts > 0 ? StrCat(MyPlayer->_pStatPts) : "") };
} },
{ N_("Gold"), { TopRightLabelX, /* set dynamically */ 0 }, 0, 98 },
{ "", { TopRightLabelX, 127 }, 99, 0,
[]() { return StyledText { UiFlags::ColorWhite, fmt::format("{:s}", FormatInteger(MyPlayer->_pGold)) }; } },
[]() { return StyledText { UiFlags::ColorWhite, FormatInteger(MyPlayer->_pGold) }; } },
{ N_("Armor class"), { RightColumnLabelX, 163 }, 57, RightColumnLabelWidth,
[]() { return StyledText { GetValueColor(MyPlayer->_pIBonusAC), fmt::format("{:d}", MyPlayer->GetArmor()) }; } },
[]() { return StyledText { GetValueColor(MyPlayer->_pIBonusAC), StrCat(MyPlayer->GetArmor()) }; } },
{ N_("To hit"), { RightColumnLabelX, 191 }, 57, RightColumnLabelWidth,
[]() { return StyledText { GetValueColor(MyPlayer->_pIBonusToHit), fmt::format("{:d}%", (MyPlayer->InvBody[INVLOC_HAND_LEFT]._itype == ItemType::Bow ? MyPlayer->GetRangedToHit() : MyPlayer->GetMeleeToHit())) }; } },
[]() { return StyledText { GetValueColor(MyPlayer->_pIBonusToHit), StrCat(MyPlayer->InvBody[INVLOC_HAND_LEFT]._itype == ItemType::Bow ? MyPlayer->GetRangedToHit() : MyPlayer->GetMeleeToHit(), "%") }; } },
{ N_("Damage"), { RightColumnLabelX, 219 }, 57, RightColumnLabelWidth,
[]() {
std::pair<int, int> dmg = GetDamage();
int spacing = ((dmg.first >= 100) ? -1 : 1);
return StyledText { GetValueColor(MyPlayer->_pIBonusDam), fmt::format("{:d}-{:d}", dmg.first, dmg.second), spacing };
return StyledText { GetValueColor(MyPlayer->_pIBonusDam), StrCat(dmg.first, "-", dmg.second), spacing };
} },
{ N_("Life"), { LeftColumnLabelX, 284 }, 45, LeftColumnLabelWidth,
[]() { return StyledText { GetMaxHealthColor(), fmt::format("{:d}", MyPlayer->_pMaxHP >> 6) }; } },
[]() { return StyledText { GetMaxHealthColor(), StrCat(MyPlayer->_pMaxHP >> 6) }; } },
{ "", { 135, 284 }, 45, 0,
[]() { return StyledText { (MyPlayer->_pHitPoints != MyPlayer->_pMaxHP ? UiFlags::ColorRed : GetMaxHealthColor()), fmt::format("{:d}", MyPlayer->_pHitPoints >> 6) }; } },
[]() { return StyledText { (MyPlayer->_pHitPoints != MyPlayer->_pMaxHP ? UiFlags::ColorRed : GetMaxHealthColor()), StrCat(MyPlayer->_pHitPoints >> 6) }; } },
{ N_("Mana"), { LeftColumnLabelX, 312 }, 45, LeftColumnLabelWidth,
[]() { return StyledText { GetMaxManaColor(), fmt::format("{:d}", MyPlayer->_pMaxMana >> 6) }; } },
[]() { return StyledText { GetMaxManaColor(), StrCat(MyPlayer->_pMaxMana >> 6) }; } },
{ "", { 135, 312 }, 45, 0,
[]() { return StyledText { (MyPlayer->_pMana != MyPlayer->_pMaxMana ? UiFlags::ColorRed : GetMaxManaColor()), fmt::format("{:d}", MyPlayer->_pMana >> 6) }; } },
[]() { return StyledText { (MyPlayer->_pMana != MyPlayer->_pMaxMana ? UiFlags::ColorRed : GetMaxManaColor()), StrCat(MyPlayer->_pMana >> 6) }; } },
{ N_("Resist magic"), { RightColumnLabelX, 256 }, 57, RightColumnLabelWidth,
[]() { return GetResistInfo(MyPlayer->_pMagResist); } },

3
Source/panels/spell_list.cpp

@ -12,6 +12,7 @@
#include "player.h"
#include "spells.h"
#include "utils/language.h"
#include "utils/str_cat.hpp"
#include "utils/utf8.hpp"
#define SPLROWICONLS 10
@ -88,7 +89,7 @@ std::optional<string_view> GetHotkeyName(spell_id spellId, spell_type spellType)
for (size_t t = 0; t < NumHotkeys; t++) {
if (myPlayer._pSplHotKey[t] != spellId || myPlayer._pSplTHotKey[t] != spellType)
continue;
auto quickSpellActionKey = fmt::format("QuickSpell{}", t + 1);
auto quickSpellActionKey = StrCat("QuickSpell", t + 1);
return sgOptions.Keymapper.KeyNameForAction(quickSpellActionKey);
}
return {};

56
Source/pfile.cpp

@ -21,6 +21,8 @@
#include "utils/file_util.h"
#include "utils/language.h"
#include "utils/paths.h"
#include "utils/stdcompat/string_view.hpp"
#include "utils/str_cat.hpp"
#include "utils/utf8.hpp"
namespace devilution {
@ -37,50 +39,20 @@ namespace {
/** List of character names for the character selection screen. */
char hero_names[MAX_CHARACTERS][PlayerNameLength];
std::string GetSavePath(uint32_t saveNum, std::string savePrefix = "")
std::string GetSavePath(uint32_t saveNum, string_view savePrefix = {})
{
std::string path = paths::PrefPath();
const char *ext = ".sv";
if (gbIsHellfire)
ext = ".hsv";
path.append(savePrefix);
if (gbIsSpawn) {
if (!gbIsMultiplayer) {
path.append("spawn_");
} else {
path.append("share_");
}
} else {
if (!gbIsMultiplayer) {
path.append("single_");
} else {
path.append("multi_");
}
}
char saveNumStr[21];
*fmt::format_to(saveNumStr, FMT_COMPILE("{}"), saveNum) = '\0';
path.append(saveNumStr);
path.append(ext);
return path;
return StrCat(paths::PrefPath(), savePrefix,
gbIsSpawn
? (gbIsMultiplayer ? "share_" : "spawn_")
: (gbIsMultiplayer ? "multi_" : "single_"),
saveNum, gbIsHellfire ? ".hsv" : ".sv");
}
std::string GetStashSavePath()
{
std::string path = paths::PrefPath();
const char *ext = ".sv";
if (gbIsHellfire)
ext = ".hsv";
if (gbIsSpawn) {
path.append("stash_spawn");
} else {
path.append("stash");
}
path.append(ext);
return path;
return StrCat(paths::PrefPath(),
gbIsSpawn ? "stash_spawn" : "stash",
gbIsHellfire ? ".hsv" : ".sv");
}
bool GetSaveNames(uint8_t index, string_view prefix, char *out)
@ -316,19 +288,19 @@ void pfile_write_hero(bool writeGameData)
void pfile_write_hero_demo(int demo)
{
std::string savePath = GetSavePath(gSaveNumber, fmt::format("demo_{}_reference_", demo));
std::string savePath = GetSavePath(gSaveNumber, StrCat("demo_", demo, "_reference_"));
auto saveWriter = MpqWriter(savePath.c_str());
pfile_write_hero(saveWriter, true);
}
HeroCompareResult pfile_compare_hero_demo(int demo)
{
std::string referenceSavePath = GetSavePath(gSaveNumber, fmt::format("demo_{}_reference_", demo));
std::string referenceSavePath = GetSavePath(gSaveNumber, StrCat("demo_", demo, "_reference_"));
if (!FileExists(referenceSavePath.c_str()))
return HeroCompareResult::ReferenceNotFound;
std::string actualSavePath = GetSavePath(gSaveNumber, fmt::format("demo_{}_actual_", demo));
std::string actualSavePath = GetSavePath(gSaveNumber, StrCat("demo_", demo, "_actual_"));
{
MpqWriter saveWriter(actualSavePath.c_str());
pfile_write_hero(saveWriter, true);

4
Source/platform/ctr/messagebox.cpp

@ -1,8 +1,8 @@
#include <3ds.h>
#include <SDL.h>
#include <fmt/core.h>
#include "utils/sdl2_to_1_2_backports.h"
#include "utils/str_cat.hpp"
int SDL_ShowSimpleMessageBox(Uint32 flags,
const char *title,
@ -13,7 +13,7 @@ int SDL_ShowSimpleMessageBox(Uint32 flags,
SDL_Log("%s", SDL_GetError());
bool init = !gspHasGpuRight();
auto text = fmt::format("{}\n\n{}", title, message);
auto text = devilution::StrCat(title, "\n\n", message);
if (init)
gfxInitDefault();

51
Source/player.cpp

@ -38,6 +38,7 @@
#include "towners.h"
#include "utils/language.h"
#include "utils/log.hpp"
#include "utils/str_cat.hpp"
#include "utils/utf8.hpp"
namespace devilution {
@ -433,7 +434,7 @@ void ChangeOffset(Player &player)
void StartAttack(int pnum, Direction d)
{
if ((DWORD)pnum >= MAX_PLRS) {
app_fatal(fmt::format("StartAttack: illegal player {}", pnum));
app_fatal(StrCat("StartAttack: illegal player ", pnum));
}
Player &player = Players[pnum];
@ -465,7 +466,7 @@ void StartAttack(int pnum, Direction d)
void StartRangeAttack(int pnum, Direction d, WorldTileCoord cx, WorldTileCoord cy)
{
if ((DWORD)pnum >= MAX_PLRS) {
app_fatal(fmt::format("StartRangeAttack: illegal player {}", pnum));
app_fatal(StrCat("StartRangeAttack: illegal player ", pnum));
}
Player &player = Players[pnum];
@ -507,7 +508,7 @@ player_graphic GetPlayerGraphicForSpell(spell_id spellId)
void StartSpell(int pnum, Direction d, WorldTileCoord cx, WorldTileCoord cy)
{
if ((DWORD)pnum >= MAX_PLRS)
app_fatal(fmt::format("StartSpell: illegal player {}", pnum));
app_fatal(StrCat("StartSpell: illegal player ", pnum));
Player &player = Players[pnum];
if (player._pInvincible && player._pHitPoints == 0 && pnum == MyPlayerId) {
@ -649,7 +650,7 @@ void InitLevelChange(int pnum)
bool DoWalk(int pnum, int variant)
{
if ((DWORD)pnum >= MAX_PLRS) {
app_fatal(fmt::format("PM_DoWalk: illegal player {}", pnum));
app_fatal(StrCat("PM_DoWalk: illegal player ", pnum));
}
Player &player = Players[pnum];
@ -802,12 +803,12 @@ bool PlrHitMonst(int pnum, int monsterId, bool adjacentDamage = false)
int hper = 0;
if ((DWORD)monsterId >= MaxMonsters) {
app_fatal(fmt::format("PlrHitMonst: illegal monster {}", monsterId));
app_fatal(StrCat("PlrHitMonst: illegal monster ", monsterId));
}
auto &monster = Monsters[monsterId];
if ((DWORD)pnum >= MAX_PLRS) {
app_fatal(fmt::format("PlrHitMonst: illegal player {}", pnum));
app_fatal(StrCat("PlrHitMonst: illegal player ", pnum));
}
Player &player = Players[pnum];
@ -984,7 +985,7 @@ bool PlrHitMonst(int pnum, int monsterId, bool adjacentDamage = false)
bool PlrHitPlr(Player &attacker, int8_t p)
{
if ((DWORD)p >= MAX_PLRS) {
app_fatal(fmt::format("PlrHitPlr: illegal target player {}", p));
app_fatal(StrCat("PlrHitPlr: illegal target player ", p));
}
Player &target = Players[p];
@ -1064,7 +1065,7 @@ bool PlrHitObj(int pnum, Object &targetObject)
bool DoAttack(int pnum)
{
if ((DWORD)pnum >= MAX_PLRS) {
app_fatal(fmt::format("PM_DoAttack: illegal player {}", pnum));
app_fatal(StrCat("PM_DoAttack: illegal player ", pnum));
}
Player &player = Players[pnum];
@ -1174,7 +1175,7 @@ bool DoAttack(int pnum)
bool DoRangeAttack(int pnum)
{
if ((DWORD)pnum >= MAX_PLRS) {
app_fatal(fmt::format("PM_DoRangeAttack: illegal player {}", pnum));
app_fatal(StrCat("PM_DoRangeAttack: illegal player ", pnum));
}
Player &player = Players[pnum];
@ -1274,7 +1275,7 @@ void DamageParryItem(Player &player)
bool DoBlock(int pnum)
{
if ((DWORD)pnum >= MAX_PLRS) {
app_fatal(fmt::format("PM_DoBlock: illegal player {}", pnum));
app_fatal(StrCat("PM_DoBlock: illegal player ", pnum));
}
Player &player = Players[pnum];
@ -1335,7 +1336,7 @@ void DamageArmor(Player &player)
bool DoSpell(int pnum)
{
if ((DWORD)pnum >= MAX_PLRS) {
app_fatal(fmt::format("PM_DoSpell: illegal player {}", pnum));
app_fatal(StrCat("PM_DoSpell: illegal player ", pnum));
}
Player &player = Players[pnum];
@ -1366,7 +1367,7 @@ bool DoSpell(int pnum)
bool DoGotHit(int pnum)
{
if ((DWORD)pnum >= MAX_PLRS) {
app_fatal(fmt::format("PM_DoGotHit: illegal player {}", pnum));
app_fatal(StrCat("PM_DoGotHit: illegal player ", pnum));
}
Player &player = Players[pnum];
@ -1437,7 +1438,7 @@ void TryDisarm(const Player &player, Object &object)
void CheckNewPath(int pnum, bool pmWillBeCalled)
{
if ((DWORD)pnum >= MAX_PLRS) {
app_fatal(fmt::format("CheckNewPath: illegal player {}", pnum));
app_fatal(StrCat("CheckNewPath: illegal player ", pnum));
}
Player &player = Players[pnum];
@ -1775,7 +1776,7 @@ bool PlrDeathModeOK(Player &player)
void ValidatePlayer()
{
if ((DWORD)MyPlayerId >= MAX_PLRS) {
app_fatal(fmt::format("ValidatePlayer: illegal player {}", MyPlayerId));
app_fatal(StrCat("ValidatePlayer: illegal player ", MyPlayerId));
}
Player &myPlayer = *MyPlayer;
@ -2845,7 +2846,7 @@ void InitPlayer(Player &player, bool firstTime)
void InitMultiView()
{
if ((DWORD)MyPlayerId >= MAX_PLRS) {
app_fatal(fmt::format("InitPlayer: illegal player {}", MyPlayerId));
app_fatal(StrCat("InitPlayer: illegal player ", MyPlayerId));
}
Player &myPlayer = *MyPlayer;
@ -2899,7 +2900,7 @@ void FixPlayerLocation(Player &player, Direction bDir)
void StartStand(int pnum, Direction dir)
{
if ((DWORD)pnum >= MAX_PLRS) {
app_fatal(fmt::format("StartStand: illegal player {}", pnum));
app_fatal(StrCat("StartStand: illegal player ", pnum));
}
Player &player = Players[pnum];
@ -2919,7 +2920,7 @@ void StartStand(int pnum, Direction dir)
void StartPlrBlock(int pnum, Direction dir)
{
if ((DWORD)pnum >= MAX_PLRS) {
app_fatal(fmt::format("StartPlrBlock: illegal player {}", pnum));
app_fatal(StrCat("StartPlrBlock: illegal player ", pnum));
}
Player &player = Players[pnum];
@ -2954,7 +2955,7 @@ void FixPlrWalkTags(const Player &player)
void StartPlrHit(int pnum, int dam, bool forcehit)
{
if ((DWORD)pnum >= MAX_PLRS) {
app_fatal(fmt::format("StartPlrHit: illegal player {}", pnum));
app_fatal(StrCat("StartPlrHit: illegal player ", pnum));
}
Player &player = Players[pnum];
@ -3006,7 +3007,7 @@ void
StartPlayerKill(int pnum, int earflag)
{
if ((DWORD)pnum >= MAX_PLRS) {
app_fatal(fmt::format("StartPlayerKill: illegal player {}", pnum));
app_fatal(StrCat("StartPlayerKill: illegal player ", pnum));
}
Player &player = Players[pnum];
@ -3214,7 +3215,7 @@ StartNewLvl(int pnum, interface_mode fom, int lvl)
InitLevelChange(pnum);
if ((DWORD)pnum >= MAX_PLRS) {
app_fatal(fmt::format("StartNewLvl: illegal player {}", pnum));
app_fatal(StrCat("StartNewLvl: illegal player ", pnum));
}
Player &player = Players[pnum];
Player &myPlayer = *MyPlayer;
@ -3254,7 +3255,7 @@ void RestartTownLvl(int pnum)
{
InitLevelChange(pnum);
if ((DWORD)pnum >= MAX_PLRS) {
app_fatal(fmt::format("RestartTownLvl: illegal player {}", pnum));
app_fatal(StrCat("RestartTownLvl: illegal player ", pnum));
}
Player &player = Players[pnum];
@ -3303,7 +3304,7 @@ void StartWarpLvl(int pnum, int pidx)
void ProcessPlayers()
{
if ((DWORD)MyPlayerId >= MAX_PLRS) {
app_fatal(fmt::format("ProcessPlayers: illegal player {}", MyPlayerId));
app_fatal(StrCat("ProcessPlayers: illegal player ", MyPlayerId));
}
Player &myPlayer = *MyPlayer;
@ -3472,7 +3473,7 @@ void CheckPlrSpell(bool isShiftHeld, spell_id spellID, spell_type spellType)
bool addflag = false;
if ((DWORD)MyPlayerId >= MAX_PLRS) {
app_fatal(fmt::format("CheckPlrSpell: illegal player {}", MyPlayerId));
app_fatal(StrCat("CheckPlrSpell: illegal player ", MyPlayerId));
}
Player &myPlayer = *MyPlayer;
@ -3648,7 +3649,7 @@ void SyncInitPlrPos(int pnum)
void SyncInitPlr(int pnum)
{
if ((DWORD)pnum >= MAX_PLRS) {
app_fatal(fmt::format("SyncInitPlr: illegal player {}", pnum));
app_fatal(StrCat("SyncInitPlr: illegal player ", pnum));
}
Player &player = Players[pnum];
@ -3829,7 +3830,7 @@ enum {
void PlayDungMsgs()
{
if ((DWORD)MyPlayerId >= MAX_PLRS) {
app_fatal(fmt::format("PlayDungMsgs: illegal player {}", MyPlayerId));
app_fatal(StrCat("PlayDungMsgs: illegal player ", MyPlayerId));
}
Player &myPlayer = *MyPlayer;

5
Source/qol/monhealthbar.cpp

@ -11,6 +11,7 @@
#include "cursor.h"
#include "options.h"
#include "utils/language.h"
#include "utils/str_cat.hpp"
namespace devilution {
namespace {
@ -117,7 +118,7 @@ void DrawMonsterHealthBar(const Surface &out)
return 150;
default:
app_fatal(fmt::format("Invalid monster class: {}", static_cast<int>(monsterClass)));
app_fatal(StrCat("Invalid monster class: ", static_cast<int>(monsterClass)));
}
};
@ -142,7 +143,7 @@ void DrawMonsterHealthBar(const Surface &out)
DrawString(out, monster.name, { position, { width, height } }, style);
if (multiplier > 0)
DrawString(out, fmt::format("x{:d}", multiplier), { position, { width - 2, height } }, UiFlags::ColorWhite | UiFlags::AlignRight | UiFlags::VerticalCenter);
DrawString(out, StrCat("x", multiplier), { position, { width - 2, height } }, UiFlags::ColorWhite | UiFlags::AlignRight | UiFlags::VerticalCenter);
if (monster.uniqType != 0 || MonsterKillCounts[monster.type().type] >= 15) {
monster_resistance immunes[] = { IMMUNE_MAGIC, IMMUNE_FIRE, IMMUNE_LIGHTNING };
monster_resistance resists[] = { RESIST_MAGIC, RESIST_FIRE, RESIST_LIGHTNING };

7
Source/qol/stash.cpp

@ -18,6 +18,7 @@
#include "stores.h"
#include "utils/format_int.hpp"
#include "utils/language.h"
#include "utils/str_cat.hpp"
#include "utils/utf8.hpp"
namespace devilution {
@ -382,8 +383,8 @@ void DrawStash(const Surface &out)
Point position = GetPanelPosition(UiPanels::Stash);
UiFlags style = UiFlags::VerticalCenter | UiFlags::ColorWhite;
DrawString(out, fmt::format("{:d}", Stash.GetPage() + 1), { position + Displacement { 132, 0 }, { 57, 11 } }, UiFlags::AlignCenter | style);
DrawString(out, fmt::format("{:s}", FormatInteger(Stash.gold)), { position + Displacement { 122, 19 }, { 107, 13 } }, UiFlags::AlignRight | style);
DrawString(out, StrCat(Stash.GetPage() + 1), { position + Displacement { 132, 0 }, { 57, 11 } }, UiFlags::AlignCenter | style);
DrawString(out, FormatInteger(Stash.gold), { position + Displacement { 122, 19 }, { 107, 13 } }, UiFlags::AlignRight | style);
}
void CheckStashItem(Point mousePosition, bool isShiftHeld, bool isCtrlHeld)
@ -631,7 +632,7 @@ void DrawGoldWithdraw(const Surface &out, int amount)
std::string value = "";
if (amount > 0) {
value = fmt::format("{:d}", amount);
value = StrCat(amount);
}
// Even a ten digit amount of gold only takes up about half a line. There's no need to wrap or clip text here so we
// use the Point form of DrawString.

5
Source/stores.cpp

@ -24,6 +24,7 @@
#include "utils/format_int.hpp"
#include "utils/language.h"
#include "utils/stdcompat/string_view.hpp"
#include "utils/str_cat.hpp"
#include "utils/utf8.hpp"
namespace devilution {
@ -1022,7 +1023,7 @@ void StoreConfirm(Item &item)
prompt = _("Are you sure you want to repair this item?");
break;
default:
app_fatal(fmt::format("Unknown store dialog {}", static_cast<int>(stextshold)));
app_fatal(StrCat("Unknown store dialog ", static_cast<int>(stextshold)));
}
AddSText(0, 15, prompt, UiFlags::ColorWhite | UiFlags::AlignCenter, false);
AddSText(0, 18, _("Yes"), UiFlags::ColorWhite | UiFlags::AlignCenter, true);
@ -2274,7 +2275,7 @@ void PrintSString(const Surface &out, int margin, int line, string_view text, Ui
const Rectangle rect { { sx, sy }, { width, 0 } };
DrawString(out, text, rect, flags);
if (price > 0)
DrawString(out, fmt::format("{:s}", FormatInteger(price)), rect, flags | UiFlags::AlignRight);
DrawString(out, FormatInteger(price), rect, flags | UiFlags::AlignRight);
if (stextsel == line) {
DrawSelector(out, rect, text, flags);

3
Source/utils/display.cpp

@ -29,6 +29,7 @@
#include "utils/log.hpp"
#include "utils/sdl_geometry.h"
#include "utils/sdl_wrap.h"
#include "utils/str_cat.hpp"
#ifdef USE_SDL1
#ifndef SDL1_VIDEO_MODE_BPP
@ -350,7 +351,7 @@ void ReinitializeTexture()
if (renderer == nullptr)
return;
auto quality = fmt::format("{}", static_cast<int>(*sgOptions.Graphics.scaleQuality));
auto quality = StrCat(static_cast<int>(*sgOptions.Graphics.scaleQuality));
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, quality.c_str());
texture = SDLWrap::CreateTexture(renderer, SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_STREAMING, gnScreenWidth, gnScreenHeight);

17
Source/utils/file_name_generator.hpp

@ -3,9 +3,8 @@
#include <cstring>
#include <initializer_list>
#include <fmt/format.h>
#include "utils/stdcompat/string_view.hpp"
#include "utils/str_cat.hpp"
namespace devilution {
@ -19,7 +18,7 @@ public:
const char *operator()() const
{
*Append(prefixEnd_, suffix_) = '\0';
*BufCopy(prefixEnd_, suffix_) = '\0';
return buf_;
}
@ -27,16 +26,10 @@ protected:
static char *Append(char *buf, std::initializer_list<string_view> strings)
{
for (string_view str : strings)
buf = Append(buf, str);
buf = BufCopy(buf, str);
return buf;
}
static char *Append(char *buf, string_view str)
{
memcpy(buf, str.data(), str.size());
return buf + str.size();
}
[[nodiscard]] string_view Suffix() const
{
return suffix_;
@ -76,7 +69,7 @@ public:
const char *operator()(size_t i) const
{
*Append(fmt::format_to(PrefixEnd(), "{}", static_cast<unsigned>(min_ + i)), Suffix()) = '\0';
*BufCopy(PrefixEnd(), static_cast<unsigned>(min_ + i), Suffix()) = '\0';
return Buffer();
}
@ -97,7 +90,7 @@ public:
: BaseFileNameGenerator(prefixes, suffix)
, chars_(chars)
{
*Append(PrefixEnd() + 1, Suffix()) = '\0';
*BufCopy(PrefixEnd() + 1, Suffix()) = '\0';
}
const char *operator()(size_t i) const

3
Source/utils/format_int.cpp

@ -5,6 +5,7 @@
#include "utils/language.h"
#include "utils/stdcompat/string_view.hpp"
#include "utils/str_cat.hpp"
namespace devilution {
@ -14,7 +15,7 @@ std::string FormatInteger(int n)
char buf[40];
char *begin = buf;
const char *end = fmt::format_to(buf, FMT_COMPILE("{}"), n);
const char *end = BufCopy(buf, n);
const size_t len = end - begin;
std::string out;

3
Source/utils/log.hpp

@ -5,6 +5,7 @@
#include <fmt/ranges.h>
#include "utils/stdcompat/string_view.hpp"
#include "utils/str_cat.hpp"
#ifdef USE_SDL1
#include "sdl2_to_1_2_backports.h"
@ -52,7 +53,7 @@ std::string format(string_view fmt, Args &&...args)
#if FMT_EXCEPTIONS
// e.what() is undefined if exceptions are disabled, so we wrap the whole block
// with an `FMT_EXCEPTIONS` check.
std::string error = fmt::format("Format error, fmt: {}, error: {}", fmt, e.what());
std::string error = StrCat("Format error, fmt: ", fmt, " error: ", e.what());
SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, "%s", error.c_str());
app_fatal(error);
#endif

28
Source/utils/str_cat.cpp

@ -0,0 +1,28 @@
#include "utils/str_cat.hpp"
#include <cstddef>
#include <fmt/compile.h>
#include <fmt/core.h>
namespace devilution {
namespace {
template <typename T>
constexpr size_t MaxDecimalDigits = 241 * sizeof(T) / 100 + 1;
} // namespace
char *BufCopy(char *out, int value)
{
return fmt::format_to(out, FMT_COMPILE("{}"), value);
}
void StrAppend(std::string &out, int value)
{
char buf[MaxDecimalDigits<int> + 1];
out.append(&buf[0], BufCopy(buf, value) - &buf[0]);
}
} // namespace devilution

82
Source/utils/str_cat.hpp

@ -0,0 +1,82 @@
#pragma once
#include <cstring>
#include <string>
#include <type_traits>
#include "utils/stdcompat/string_view.hpp"
namespace devilution {
/**
* @brief Writes the integer to the given buffer.
* @return char* end of the buffer
*/
char *BufCopy(char *out, int value);
/**
* @brief Appends the integer to the given string.
*/
void StrAppend(std::string &out, int value);
/**
* @brief Copies the given string_view to the given buffer.
*/
inline char *BufCopy(char *out, string_view value)
{
std::memcpy(out, value.data(), value.size());
return out + value.size();
}
/**
* @brief Copies the given string_view to the given string.
*/
inline void StrAppend(std::string &out, string_view value)
{
out.append(value.data(), value.size());
}
/**
* @brief Appends the given C string to the given buffer.
*
* `str` must be a null-terminated C string, `out` will not be null terminated.
*/
inline char *BufCopy(char *out, const char *str)
{
return BufCopy(out, string_view(str != nullptr ? str : "(nullptr)"));
}
/**
* @brief Appends the given C string to the given string.
*/
inline void StrAppend(std::string &out, const char *str)
{
if (str == nullptr)
out.append("(nullptr)");
out.append(str, string_view(str).size());
}
template <typename Arg, typename... Args>
inline typename std::enable_if<(sizeof...(Args) > 0), char *>::type
BufCopy(char *out, Arg &&arg, Args &&...args)
{
return BufCopy(BufCopy(out, std::forward<Arg>(arg)), std::forward<Args>(args)...);
}
template <typename Arg, typename... Args>
inline typename std::enable_if<(sizeof...(Args) > 0), void>::type
StrAppend(std::string &out, Arg &&arg, Args &&...args)
{
StrAppend(out, std::forward<Arg>(arg));
StrAppend(out, std::forward<Args>(args)...);
}
template <typename... Args>
std::string StrCat(Args &&...args)
{
std::string result;
StrAppend(result, std::forward<Args>(args)...);
return result;
}
} // namespace devilution
Loading…
Cancel
Save