Replace libfmt with std::format

- `fmt::format` with literal format strings -> `std::format`.
- `fmt::format(fmt::runtime(...))` -> `FormatRuntime` in the new
  `utils/format.hpp`, a std::vformat wrapper that is also safe under the
  P2905 lvalue requirement of `std::make_format_args`.
- `fmt::dynamic_format_arg_store` (Lua logging) -> a small hand-rolled
  per-field formatter over `std::variant`, returning `std::expected`.
- `fmt::format_int` -> `std::to_chars`.
- `fmt::join` -> manual joins at the two call sites.
- SDL_audiolib: new patch that rewrites aulib_log.h to use std::format
  and drops the fmt dependency from its CMakeLists.
- The `-static-libstdc++` guard now keys off
  `DEVILUTIONX_STATIC_SDL_AUDIOLIB` instead of `DEVILUTIONX_STATIC_LIBFMT`.
- libfmt removed from CMake, vcpkg, Brewfile, CI workflows,
  Dockerfiles, packaging scripts, UWP project, and docs.
- macOS bumped to 13.3+, iOS to 16.3+ (required for `<format>`)
- Amiga m68k: provide `__cmpdf2`, which is missing from the hard-float
  libgcc multilib but referenced via libstdc++'s long double paths.

Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
Gleb MazovetskiyandClaude Fable 5 authored and Anders Jenbo committed 2026-07-22 00:00:04 +02:00
1 parent c00b5f44da
commit ac2d7fc731
109 files changed
+692 -662

No files matched your search

+1 -1
View File
@@ -7,7 +7,7 @@ RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
&& apt-get -y install tar curl zip unzip bash-completion build-essential ripgrep htop \
ninja-build ccache g++ mold gdb clang-format clang-tidy \
rpm pkg-config cmake git gettext libsdl2-dev libsdl2-image-dev libsodium-dev \
libpng-dev libbz2-dev libfmt-dev libgtest-dev libgmock-dev libbenchmark-dev zsh \
libpng-dev libbz2-dev libgtest-dev libgmock-dev libbenchmark-dev zsh \
qtbase5-dev qt6-base-dev ristretto \
&& apt-get autoremove -y && apt-get clean -y && rm -rf /var/lib/apt/lists/*
+2 -2
View File
@@ -44,8 +44,8 @@ jobs:
uses: actions/cache@v6
with:
path: android-project/app/.cxx
key: ${{ github.workflow }}-v5-${{ github.sha }}
restore-keys: ${{ github.workflow }}-v5-
key: ${{ github.workflow }}-v6-${{ github.sha }}
restore-keys: ${{ github.workflow }}-v6-
- name: Build
working-directory: ${{github.workspace}}
+3 -4
View File
@@ -40,20 +40,19 @@ jobs:
uses: actions/cache@v6
with:
path: build
key: ${{ github.workflow }}-v8-${{ github.sha }}
restore-keys: ${{ github.workflow }}-v8-
key: ${{ github.workflow }}-v9-${{ github.sha }}
restore-keys: ${{ github.workflow }}-v9-
- name: Build
working-directory: ${{github.workspace}}
shell: bash
env:
CMAKE_BUILD_TYPE: ${{github.event_name == 'release' && 'Release' || 'RelWithDebInfo'}}
# We set DEVILUTIONX_SYSTEM_LIBFMT=OFF because its soversion changes frequently.
# We set DEVILUTIONX_SYSTEM_LIBSODIUM=OFF because its soversion changes frequently.
# We set DEVILUTIONX_SYSTEM_BZIP2=OFF because Fedora and Debian do not agree on how to link it.
run: |
cmake -S. -Bbuild -DCMAKE_TOOLCHAIN_FILE=../CMake/platforms/aarch64-linux-gnu.toolchain.cmake \
-DCMAKE_BUILD_TYPE=${{env.CMAKE_BUILD_TYPE}} -DCMAKE_INSTALL_PREFIX=/usr -DCPACK=ON -DDEVILUTIONX_SYSTEM_LIBFMT=OFF \
-DCMAKE_BUILD_TYPE=${{env.CMAKE_BUILD_TYPE}} -DCMAKE_INSTALL_PREFIX=/usr -DCPACK=ON \
-DDEVILUTIONX_SYSTEM_LIBSODIUM=OFF -DDEVILUTIONX_SYSTEM_BZIP2=OFF && \
cmake --build build -j $(getconf _NPROCESSORS_ONLN) --target package
+3 -4
View File
@@ -40,21 +40,20 @@ jobs:
uses: actions/cache@v6
with:
path: build
key: ${{ github.workflow }}-v7-${{ github.sha }}
restore-keys: ${{ github.workflow }}-v7-
key: ${{ github.workflow }}-v8-${{ github.sha }}
restore-keys: ${{ github.workflow }}-v8-
- name: Build
working-directory: ${{github.workspace}}
shell: bash
env:
CMAKE_BUILD_TYPE: ${{github.event_name == 'release' && 'Release' || 'RelWithDebInfo'}}
# We set DEVILUTIONX_SYSTEM_LIBFMT=OFF because its soversion changes frequently.
# We set DEVILUTIONX_SYSTEM_LIBSODIUM=OFF because its soversion changes frequently.
# We set DEVILUTIONX_SYSTEM_BZIP2=OFF because Fedora and Debian do not agree on how to link it.
run: |
cmake -S. -Bbuild -DCMAKE_TOOLCHAIN_FILE=../CMake/platforms/linux_i386.toolchain.cmake \
-DCMAKE_BUILD_TYPE=${{env.CMAKE_BUILD_TYPE}} -DCMAKE_INSTALL_PREFIX=/usr -DCPACK=ON \
-DBUILD_TESTING=OFF -DDEVILUTIONX_SYSTEM_LIBFMT=OFF -DDEVILUTIONX_SYSTEM_LIBSODIUM=OFF \
-DBUILD_TESTING=OFF -DDEVILUTIONX_SYSTEM_LIBSODIUM=OFF \
-DDEVILUTIONX_SYSTEM_BZIP2=OFF && \
cmake --build build -j $(getconf _NPROCESSORS_ONLN) --target package
+3 -4
View File
@@ -40,20 +40,19 @@ jobs:
uses: actions/cache@v6
with:
path: build
key: ${{ github.workflow }}-v7-${{ github.sha }}
restore-keys: ${{ github.workflow }}-v7-
key: ${{ github.workflow }}-v8-${{ github.sha }}
restore-keys: ${{ github.workflow }}-v8-
- name: Build
working-directory: ${{github.workspace}}
shell: bash
env:
CMAKE_BUILD_TYPE: ${{github.event_name == 'release' && 'Release' || 'RelWithDebInfo'}}
# We set DEVILUTIONX_SYSTEM_LIBFMT=OFF because its soversion changes frequently.
# We set DEVILUTIONX_SYSTEM_LIBSODIUM=OFF because its soversion changes frequently.
# We set DEVILUTIONX_SYSTEM_BZIP2=OFF because Fedora and Debian do not agree on how to link it.
run: |
cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=${{env.CMAKE_BUILD_TYPE}} -DCMAKE_INSTALL_PREFIX=/usr -DCPACK=ON \
-DDISCORD_INTEGRATION=ON -DBUILD_TESTING=OFF -DDEVILUTIONX_SYSTEM_LIBFMT=OFF \
-DDISCORD_INTEGRATION=ON -DBUILD_TESTING=OFF \
-DDEVILUTIONX_SYSTEM_LIBSODIUM=OFF -DDEVILUTIONX_SYSTEM_BZIP2=OFF && \
cmake --build build -j $(getconf _NPROCESSORS_ONLN) --target package
+3 -3
View File
@@ -29,14 +29,14 @@ jobs:
- name: Create Build Environment
run: >
sudo apt-get update &&
sudo apt-get install -y cmake file g++ gettext git libfmt-dev libsdl1.2-dev libsodium-dev libpng-dev libbz2-dev rpm smpq
sudo apt-get install -y cmake file g++ gettext git libsdl1.2-dev libsodium-dev libpng-dev libbz2-dev rpm smpq
- name: Cache CMake build folder
uses: actions/cache@v6
with:
path: build
key: ${{ github.workflow }}-v3-${{ github.sha }}
restore-keys: ${{ github.workflow }}-v3-
key: ${{ github.workflow }}-v4-${{ github.sha }}
restore-keys: ${{ github.workflow }}-v4-
- name: Configure CMake
shell: bash
+3 -3
View File
@@ -30,14 +30,14 @@ jobs:
- name: Install dependencies
run: |
sudo apt-get update -y
sudo apt-get install -y cmake curl g++ git libgtest-dev libgmock-dev libbenchmark-dev libfmt-dev libsodium-dev libpng-dev libbz2-dev libasound2-dev libxcursor-dev libxi-dev libxrandr-dev libxss-dev libxtst-dev libxkbcommon-dev wget
sudo apt-get install -y cmake curl g++ git libgtest-dev libgmock-dev libbenchmark-dev libsodium-dev libpng-dev libbz2-dev libasound2-dev libxcursor-dev libxi-dev libxrandr-dev libxss-dev libxtst-dev libxkbcommon-dev wget
- name: Cache CMake build folder
uses: actions/cache@v6
with:
path: build
key: ${{ github.workflow }}-v4-${{ github.sha }}
restore-keys: ${{ github.workflow }}-v4-
key: ${{ github.workflow }}-v5-${{ github.sha }}
restore-keys: ${{ github.workflow }}-v5-
# We specify `-DDEVILUTIONX_SYSTEM_BENCHMARK=OFF` to work around the following error:
# lto1: fatal error: bytecode stream in file ‘/usr/lib/x86_64-linux-gnu/libbenchmark_main.a’ generated with LTO version 11.2 instead of the expected 11.3
+3 -3
View File
@@ -30,14 +30,14 @@ jobs:
- name: Install dependencies
run: |
sudo apt-get update -y
sudo apt-get install -y cmake curl g++ git lcov libgtest-dev libgmock-dev libbenchmark-dev libfmt-dev libsdl2-dev libsodium-dev libpng-dev libbz2-dev wget
sudo apt-get install -y cmake curl g++ git lcov libgtest-dev libgmock-dev libbenchmark-dev libsdl2-dev libsodium-dev libpng-dev libbz2-dev wget
- name: Cache CMake build folder
uses: actions/cache@v6
with:
path: build
key: ${{ github.workflow }}-v3-${{ github.sha }}
restore-keys: ${{ github.workflow }}-v3-
key: ${{ github.workflow }}-v4-${{ github.sha }}
restore-keys: ${{ github.workflow }}-v4-
# We specify `-DDEVILUTIONX_SYSTEM_BENCHMARK=OFF` to work around the following error:
# lto1: fatal error: bytecode stream in file ‘/usr/lib/x86_64-linux-gnu/libbenchmark_main.a’ generated with LTO version 11.2 instead of the expected 11.3
-1
View File
@@ -67,7 +67,6 @@ jobs:
path: |
build-ninja-vcpkg-relwithdebinfo/devilutionx.exe
build-ninja-vcpkg-relwithdebinfo/bz2.dll
build-ninja-vcpkg-relwithdebinfo/fmt.dll
build-ninja-vcpkg-relwithdebinfo/libpng16.dll
build-ninja-vcpkg-relwithdebinfo/libsodium.dll
build-ninja-vcpkg-relwithdebinfo/SDL2.dll
+1 -1
View File
@@ -25,7 +25,7 @@ jobs:
- name: Install dependencies
run: |
sudo apt-get update -y
sudo apt-get install -y cmake curl g++ git libgtest-dev libgmock-dev libbenchmark-dev libfmt-dev libsdl2-dev libsodium-dev libpng-dev libbz2-dev wget
sudo apt-get install -y cmake curl g++ git libgtest-dev libgmock-dev libbenchmark-dev libsdl2-dev libsodium-dev libpng-dev libbz2-dev wget
- name: CMake Configure
run: cmake -S. -Bbuild
+2 -2
View File
@@ -39,8 +39,8 @@ jobs:
uses: actions/cache@v6
with:
path: build
key: ${{ github.workflow }}-v5-${{ github.sha }}
restore-keys: ${{ github.workflow }}-v5-
key: ${{ github.workflow }}-v6-${{ github.sha }}
restore-keys: ${{ github.workflow }}-v6-
- name: Configure CMake
# Use a bash shell so we can use the same syntax for environment variable
+2 -2
View File
@@ -38,8 +38,8 @@ jobs:
uses: actions/cache@v6
with:
path: build
key: ${{ github.workflow }}-v2-${{ github.sha }}
restore-keys: ${{ github.workflow }}-v2-
key: ${{ github.workflow }}-v3-${{ github.sha }}
restore-keys: ${{ github.workflow }}-v3-
- name: Clean previous DMG
working-directory: ${{github.workspace}}
+2 -2
View File
@@ -38,8 +38,8 @@ jobs:
uses: actions/cache@v6
with:
path: build
key: ${{ github.workflow }}-v4-${{ github.sha }}
restore-keys: ${{ github.workflow }}-v4-
key: ${{ github.workflow }}-v5-${{ github.sha }}
restore-keys: ${{ github.workflow }}-v5-
- name: Clean previous DMG
working-directory: ${{github.workspace}}
@@ -36,7 +36,7 @@ jobs:
run: >
docker run --platform linux/s390x --rm --interactive --mount type=bind,source=$(pwd),target=/host s390x/alpine sh -c
"
apk add --update-cache g++ ninja cmake ccache sdl2-dev sdl2_image-dev fmt-dev libpng-dev jpeg-dev bzip2-dev gtest-dev wget &&
apk add --update-cache g++ ninja cmake ccache sdl2-dev sdl2_image-dev libpng-dev jpeg-dev bzip2-dev gtest-dev wget &&
cd /host &&
export CCACHE_DIR=/host/.ccache &&
cmake -S. -Bbuild -G Ninja -DNONET=ON -DNOSOUND=ON &&
+2 -2
View File
@@ -24,7 +24,7 @@ jobs:
- name: Create Build Environment
run: >
sudo apt-get update &&
sudo apt-get install -y cmake curl libsdl2-dev libsdl2-image-dev libfmt-dev libsodium-dev libbz2-dev libgtest-dev libgmock-dev libbenchmark-dev git smpq gettext python-is-python3
sudo apt-get install -y cmake curl libsdl2-dev libsdl2-image-dev libsodium-dev libbz2-dev libgtest-dev libgmock-dev libbenchmark-dev git smpq gettext python-is-python3
- name: Build
working-directory: ${{github.workspace}}
@@ -55,7 +55,7 @@ jobs:
- name: Create Build Environment
run: >
sudo apt-get update &&
sudo apt-get install -y cmake curl libsdl2-dev libsdl2-image-dev libfmt-dev libsodium-dev libbz2-dev libgtest-dev libgmock-dev libbenchmark-dev git smpq gettext python-is-python3
sudo apt-get install -y cmake curl libsdl2-dev libsdl2-image-dev libsodium-dev libbz2-dev libgtest-dev libgmock-dev libbenchmark-dev git smpq gettext python-is-python3
- name: Build
working-directory: ${{github.workspace}}
@@ -1,25 +0,0 @@
From e89e20a71e824a182c1ba519a9f4004686ed2433 Mon Sep 17 00:00:00 2001
From: Gleb Mazovetskiy <[email protected]>
Date: Sun, 28 Jun 2026 22:50:06 +0100
Subject: [PATCH] aulib_log.h: Include missing <fmt/format.h>
This include was missing and this started causing an error recently in our CI
---
src/aulib_log.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/aulib_log.h b/src/aulib_log.h
index b87ee7d..bfd8652 100644
--- a/src/aulib_log.h
+++ b/src/aulib_log.h
@@ -2,6 +2,7 @@
#pragma once
#include "aulib_config.h"
#include <fmt/core.h>
+#include <fmt/format.h>
namespace aulib {
namespace log {
--
2.53.0
+12 -5
View File
@@ -6,9 +6,6 @@ else()
set(BUILD_SHARED_LIBS ON)
endif()
# Will use our `fmt::fmt` target if it exists.
set(WITH_SYSTEM_FMTLIB ON)
# No need for the libsamplerate resampler:
set(USE_RESAMP_SRC OFF)
@@ -36,13 +33,23 @@ set(USE_DEC_WILDMIDI OFF)
set(USE_DEC_ADLMIDI OFF)
set(USE_DEC_DRMP3 ON)
find_package(Patch REQUIRED)
# SDL_audiolib only uses fmt in aulib_log.h, which we replace with a
# std::format version below. Pretend that fmt is already provided so that
# SDL_audiolib does not require or build it (linking the empty INTERFACE
# target is a no-op).
set(WITH_SYSTEM_FMTLIB ON)
if(NOT TARGET fmt::fmt)
add_library(devilutionx_fmt_stub INTERFACE)
add_library(fmt::fmt ALIAS devilutionx_fmt_stub)
endif()
include(FetchContent)
FetchContent_Declare_ExcludeFromAll(SDL_audiolib
URL https://github.com/realnc/SDL_audiolib/archive/cc1bb6af8d4cf5e200259072bde1edd1c8c5137e.tar.gz
URL_HASH MD5=0e8174264ac9c6b314c6b2d9a5f72efd
PATCH_COMMAND "${Patch_EXECUTABLE}" -p1 -N < "${CMAKE_CURRENT_LIST_DIR}/0001-aulib_log.h-Include-missing-fmt-format.h.patch" || true
# A file replacement instead of a diff: unlike the `patch` tool, this is
# idempotent and works the same on every host platform.
PATCH_COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_LIST_DIR}/aulib_log.h" <SOURCE_DIR>/src/aulib_log.h
)
FetchContent_MakeAvailable_ExcludeFromAll(SDL_audiolib)
+76
View File
@@ -0,0 +1,76 @@
// This is copyrighted software. More information is at the end of this file.
#pragma once
#include "aulib_config.h"
#include <cstdio>
#include <format>
#include <string>
#include <utility>
namespace aulib {
namespace log {
template <typename... Args>
void debug([[maybe_unused]] std::format_string<Args...> fmt_str,
[[maybe_unused]] Args &&...args) {
#if AULIB_DEBUG
const std::string message = std::format(fmt_str, std::forward<Args>(args)...);
std::fprintf(stderr, "SDL_audiolib debug: %s", message.c_str());
#endif
}
template <typename... Args>
void debugLn([[maybe_unused]] std::format_string<Args...> fmt_str,
[[maybe_unused]] Args &&...args) {
#if AULIB_DEBUG
const std::string message = std::format(fmt_str, std::forward<Args>(args)...);
std::fprintf(stderr, "SDL_audiolib debug: %s\n", message.c_str());
#endif
}
template <typename... Args>
void warn(std::format_string<Args...> fmt_str, Args &&...args) {
const std::string message = std::format(fmt_str, std::forward<Args>(args)...);
std::fprintf(stderr, "SDL_audiolib warning: %s", message.c_str());
}
template <typename... Args>
void warnLn(std::format_string<Args...> fmt_str, Args &&...args) {
const std::string message = std::format(fmt_str, std::forward<Args>(args)...);
std::fprintf(stderr, "SDL_audiolib warning: %s\n", message.c_str());
}
template <typename... Args>
void info(std::format_string<Args...> fmt_str, Args &&...args) {
const std::string message = std::format(fmt_str, std::forward<Args>(args)...);
std::printf("SDL_audiolib info: %s", message.c_str());
}
template <typename... Args>
void infoLn(std::format_string<Args...> fmt_str, Args &&...args) {
const std::string message = std::format(fmt_str, std::forward<Args>(args)...);
std::printf("SDL_audiolib info: %s\n", message.c_str());
}
} // namespace log
} // namespace aulib
/*
Copyright (C) 2022 Nikos Chantziaras.
This file is part of SDL_audiolib.
SDL_audiolib is free software: you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option) any
later version.
SDL_audiolib is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details.
You should have received a copy of the GNU Lesser General Public License
along with SDL_audiolib. If not, see <http://www.gnu.org/licenses/>.
*/
-39
View File
@@ -1,39 +0,0 @@
include(functions/FetchContent_ExcludeFromAll_backport)
if(NOT WIN32 AND NOT APPLE AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL FreeBSD)
# Enable POSIX extensions such as `readlink` and `ftruncate`.
add_definitions(-D_POSIX_C_SOURCE=200809L)
endif()
# Disable fmt/os.h functionality.
# We do not use it and it is not supported on some systems.
set(FMT_OS OFF)
if(DEVILUTIONX_STATIC_LIBFMT)
set(BUILD_SHARED_LIBS OFF)
else()
set(BUILD_SHARED_LIBS ON)
endif()
include(FetchContent)
FetchContent_Declare_ExcludeFromAll(libfmt
URL https://github.com/fmtlib/fmt/releases/download/12.0.0/fmt-12.0.0.zip
URL_HASH SHA256=1c32293203449792bf8e94c7f6699c643887e826f2d66a80869b4f279fb07d25
)
FetchContent_MakeAvailable_ExcludeFromAll(libfmt)
# We do not use locale-specific features of libfmt and disabling them reduces the size.
target_compile_definitions(fmt PUBLIC FMT_USE_LOCALE=0)
if(DEVILUTIONX_WINDOWS_NO_WCHAR)
target_compile_definitions(fmt PUBLIC FMT_USE_WRITE_CONSOLE)
endif()
# Reduces the overall binary size by 8 KiB.
if(TARGET_PLATFORM STREQUAL "rg99")
target_compile_definitions(fmt PUBLIC FMT_BUILTIN_TYPES=0)
endif()
# https://github.com/fmtlib/fmt/issues/4189
if(NINTENDO_3DS OR NINTENDO_SWITCH OR VITA)
target_compile_definitions(fmt PUBLIC FMT_USE_FALLBACK_FILE=1)
endif()
-1
View File
@@ -1,5 +1,4 @@
brew "cmake"
brew "fmt"
brew "sdl2"
brew "libsodium"
brew "pkg-config"
-16
View File
@@ -179,22 +179,6 @@ else()
endif()
endif()
if(NOT DEFINED DEVILUTIONX_SYSTEM_LIBFMT)
find_package(fmt 8.0.0 QUIET)
if(fmt_FOUND)
message("-- Found fmt ${fmt_VERSION}")
else()
message("-- Suitable system fmt package not found, will use fmt from source")
set(DEVILUTIONX_SYSTEM_LIBFMT OFF)
endif()
endif()
dependency_options("libfmt" DEVILUTIONX_SYSTEM_LIBFMT ON DEVILUTIONX_STATIC_LIBFMT)
if(DEVILUTIONX_SYSTEM_LIBFMT)
find_package(fmt 8.0.0 REQUIRED)
else()
add_subdirectory(3rdParty/libfmt)
endif()
if(NOT NOSOUND)
if(USE_SDL3)
if(NOT DEFINED DEVILUTIONX_SYSTEM_SDL_MIXER)
-3
View File
@@ -106,8 +106,5 @@ if(CMAKE_SYSTEM_NAME MATCHES "Darwin")
# For older macOS, we assume MacPorts because Homebrew only supports newer version
if(DARWIN_MAJOR_VERSION VERSION_LESS 11)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/platforms/macports/finders")
# On MacPorts, libfmt is in a subdirectory:
list(APPEND CMAKE_MODULE_PATH "/opt/local/lib/libfmt11/cmake")
endif()
endif()
-1
View File
@@ -163,7 +163,6 @@ if(DEVILUTIONX_SCREENSHOT_FORMAT STREQUAL DEVILUTIONX_SCREENSHOT_FORMAT_PNG AND
DevilutionX::SDL
GTest::gmock
GTest::gtest
fmt::fmt
tl
app_fatal_for_testing
language_for_testing
-1
View File
@@ -18,7 +18,6 @@ set(DEVILUTIONX_SYSTEM_SDL_IMAGE OFF)
set(DEVILUTIONX_SYSTEM_SDL_AUDIOLIB OFF)
set(DEVILUTIONX_SYSTEM_LIBSODIUM OFF)
set(DEVILUTIONX_SYSTEM_LIBPNG OFF)
set(DEVILUTIONX_SYSTEM_LIBFMT OFF)
set(DEVILUTIONX_SYSTEM_BZIP2 OFF)
# Package the assets with the APK.
-1
View File
@@ -7,7 +7,6 @@ set(PACKET_ENCRYPTION OFF)
set(DEFAULT_PER_PIXEL_LIGHTING false)
set(DEVILUTIONX_SYSTEM_BZIP2 OFF)
set(DEVILUTIONX_SYSTEM_LIBFMT OFF)
set(DEVILUTIONX_SYSTEM_ZLIB OFF)
set(DEVILUTIONX_STATIC_ZLIB ON)
set(USE_SDL3 ON)
-1
View File
@@ -4,7 +4,6 @@ set(DISABLE_ZERO_TIER ON)
set(DISABLE_TCP ON)
set(DEVILUTIONX_SYSTEM_SDL_AUDIOLIB OFF)
set(DEVILUTIONX_SYSTEM_LIBSODIUM OFF)
set(DEVILUTIONX_SYSTEM_LIBFMT OFF)
set(NOEXIT ON)
# Emscripten ports do have a bzip2 but it fails to link with this error:
# warning: _BZ2_bzDecompress may need to be added to EXPORTED_FUNCTIONS if it arrives from a system library
-1
View File
@@ -10,7 +10,6 @@ set(DEVILUTIONX_SYSTEM_SDL_IMAGE OFF)
set(DEVILUTIONX_SYSTEM_SDL_AUDIOLIB OFF)
set(DEVILUTIONX_SYSTEM_LIBSODIUM OFF)
set(DEVILUTIONX_SYSTEM_LIBPNG OFF)
set(DEVILUTIONX_SYSTEM_LIBFMT OFF)
set(NOEXIT ON)
-5
View File
@@ -8,11 +8,6 @@ set(USE_SDL1 ON)
# ZeroTier is yet to be tested.
set(DISABLE_ZERO_TIER ON)
# Use vendored libfmt until this issue is resolved:
# https://trac.macports.org/ticket/71503
set(DEVILUTIONX_SYSTEM_LIBFMT OFF)
set(DEVILUTIONX_STATIC_LIBFMT ON)
# https://trac.macports.org/ticket/71511
set(DEVILUTIONX_SYSTEM_GOOGLETEST OFF)
set(DEVILUTIONX_STATIC_GOOGLETEST OFF)
-1
View File
@@ -1,6 +1,5 @@
set(USE_SDL1 ON)
set(NONET ON)
set(DEVILUTIONX_SYSTEM_LIBFMT OFF)
set(DEVILUTIONX_SYSTEM_LIBSODIUM OFF)
set(DEVILUTIONX_SYSTEM_BZIP2 OFF)
-2
View File
@@ -4,9 +4,7 @@ set(UBSAN OFF)
set(BUILD_TESTING OFF)
set(BUILD_ASSETS_MPQ OFF)
set(DEVILUTIONX_SYSTEM_LIBSODIUM OFF)
set(DEVILUTIONX_SYSTEM_LIBFMT OFF)
set(DEVILUTIONX_STATIC_LIBSODIUM ON)
set(DEVILUTIONX_STATIC_LIBFMT ON)
set(DISABLE_ZERO_TIER ON)
set(MPQFS_FILE_BUFFER_SIZE 32768)
set(NOEXIT ON)
-2
View File
@@ -11,7 +11,6 @@ set(DEVILUTIONX_SYSTEM_SDL_IMAGE OFF)
set(DEVILUTIONX_SYSTEM_SDL_AUDIOLIB OFF)
set(DEVILUTIONX_SYSTEM_LIBSODIUM OFF)
set(DEVILUTIONX_SYSTEM_LIBPNG OFF)
set(DEVILUTIONX_SYSTEM_LIBFMT OFF)
set(DEVILUTIONX_SYSTEM_BZIP2 OFF)
set(DEVILUTIONX_SYSTEM_ZLIB OFF)
@@ -20,7 +19,6 @@ set(DEVILUTIONX_STATIC_SDL_IMAGE ON)
set(DEVILUTIONX_STATIC_SDL_AUDIOLIB ON)
set(DEVILUTIONX_STATIC_LIBSODIUM ON)
set(DEVILUTIONX_STATIC_LIBPNG ON)
set(DEVILUTIONX_STATIC_LIBFMT ON)
set(DEVILUTIONX_STATIC_BZIP2 ON)
set(DEVILUTIONX_STATIC_ZLIB ON)
-1
View File
@@ -6,7 +6,6 @@ set(NONET ON)
set(DISABLE_ZERO_TIER ON)
set(USE_SDL1 ON)
set(DEVILUTIONX_SYSTEM_BZIP2 OFF)
set(DEVILUTIONX_SYSTEM_LIBFMT OFF)
set(DEVILUTIONX_STATIC_LIBSODIUM OFF)
# Compatibility with Windows 9x 8-bit mode and improved performance
-1
View File
@@ -5,7 +5,6 @@ set(UBSAN OFF)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/xbox_nxdk/finders")
set(DEVILUTIONX_SYSTEM_BZIP2 OFF)
set(DEVILUTIONX_SYSTEM_LIBFMT OFF)
# nxdk's zlib is built with Z_SOLO, which excludes utility functions like
# uncompress() that mpqfs needs for zlib-compressed MPQ sectors.
+15 -3
View File
@@ -73,6 +73,14 @@ if(NOT VERSION_SUFFIX)
endif()
endif()
# The iOS toolchain file reads DEPLOYMENT_TARGET when it is processed by
# `project()`, so the default must be set before that.
# libc++'s <format> requires the floating-point std::to_chars symbols,
# which are only available in the iOS 16.3+ system libc++.
if(CMAKE_TOOLCHAIN_FILE MATCHES "ios\\.toolchain\\.cmake" AND NOT DEFINED DEPLOYMENT_TARGET)
set(DEPLOYMENT_TARGET "16.3")
endif()
project(DevilutionX
VERSION ${VERSION_NUM}
LANGUAGES C CXX)
@@ -355,7 +363,7 @@ include(Dependencies)
# Mixing `-static-libstdc++` with a dynamic C++ dependency causes both copies
# to initialize, which is UB and can cause crashes, e.g. in
# `std::ios_base_library_init()`.
if(NOT DEVILUTIONX_STATIC_LIBFMT)
if(NOT NOSOUND AND NOT DEVILUTIONX_STATIC_SDL_AUDIOLIB)
set(DEVILUTIONX_STATIC_CXX_STDLIB OFF)
endif()
@@ -448,10 +456,14 @@ if(APPLE)
if(IOS)
set(MACOSX_BUNDLE_REQUIRED_PLATFORM IPhoneOS)
set_target_properties(${BIN_TARGET} PROPERTIES XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "1,2")
set(CMAKE_OSX_DEPLOYMENT_TARGET "9.0")
# libc++'s <format> requires the floating-point std::to_chars symbols,
# which are only available in the iOS 16.3+ system libc++.
set(CMAKE_OSX_DEPLOYMENT_TARGET "16.3")
elseif(DARWIN_MAJOR_VERSION GREATER_EQUAL 17)
set(MACOSX_BUNDLE_REQUIRED_PLATFORM Carbon)
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.13.0")
# libc++'s <format> requires the floating-point std::to_chars symbols,
# which are only available in the macOS 13.3+ system libc++.
set(CMAKE_OSX_DEPLOYMENT_TARGET "13.3")
endif()
if(DARWIN_MAJOR_VERSION VERSION_LESS 9)
# Finder on OSX Tiger can only handle icns files with up to 128x128 icons.
-1
View File
@@ -201,7 +201,6 @@ cmake_configure() {
"-DTARGET_PLATFORM=$TARGET" \
-DCMAKE_TOOLCHAIN_FILE="${TOOLCHAIN}/usr/share/buildroot/toolchainfile.cmake" \
-DBUILD_TESTING=OFF \
-DDEVILUTIONX_SYSTEM_LIBFMT=OFF \
-DDEVILUTIONX_SYSTEM_LIBSODIUM=OFF \
-DDEVILUTIONX_SYSTEM_BZIP2=OFF \
-DSTACK_PROTECTOR=OFF \
+1 -1
View File
@@ -22,7 +22,7 @@ fi
PACKAGES=(
cmake git smpq gettext dpkg-cross libc-dev-arm64-cross
libsdl2-dev:arm64 libsdl2-image-dev:arm64 libsodium-dev:arm64
libpng-dev:arm64 libbz2-dev:arm64 libfmt-dev:arm64
libpng-dev:arm64 libbz2-dev:arm64
libspeechd-dev:arm64
)
+1 -1
View File
@@ -21,7 +21,7 @@ fi
PACKAGES=(
cmake git smpq gettext
libsdl2-dev:i386 libsdl2-image-dev:i386 libsodium-dev:i386
libpng-dev:i386 libbz2-dev:i386 libfmt-dev:i386 libspeechd-dev:i386
libpng-dev:i386 libbz2-dev:i386 libspeechd-dev:i386
)
if (( $# < 1 )) || [[ "$1" != --no-gcc ]]; then
+1 -1
View File
@@ -4,7 +4,7 @@ set -x
PACKAGES=(
rpm pkg-config cmake git smpq gettext libsdl2-dev libsdl2-image-dev libsodium-dev
libpng-dev libbz2-dev libfmt-dev libspeechd-dev
libpng-dev libbz2-dev libspeechd-dev
)
if (( $# < 1 )) || [[ "$1" != --no-gcc ]]; then
+6 -18
View File
@@ -200,7 +200,6 @@ add_devilutionx_object_library(libdevilutionx_assets
)
target_link_dependencies(libdevilutionx_assets PUBLIC
DevilutionX::SDL
fmt::fmt
tl
libdevilutionx_headless_mode
libdevilutionx_game_mode
@@ -233,7 +232,6 @@ add_devilutionx_object_library(libdevilutionx_clx_render
)
target_link_dependencies(libdevilutionx_clx_render PUBLIC
DevilutionX::SDL
fmt::fmt
libdevilutionx_light_render
libdevilutionx_palette_blending
libdevilutionx_strings
@@ -262,7 +260,6 @@ target_link_dependencies(libdevilutionx_control
tl
libdevilutionx_text_input
PRIVATE
fmt::fmt
libdevilutionx_clx_render
libdevilutionx_control_mode
libdevilutionx_format_int
@@ -404,7 +401,6 @@ add_devilutionx_object_library(libdevilutionx_gendung
)
target_link_dependencies(libdevilutionx_gendung PUBLIC
DevilutionX::SDL
fmt::fmt
tl
libdevilutionx_assets
libdevilutionx_items
@@ -508,7 +504,6 @@ add_devilutionx_object_library(libdevilutionx_lighting
)
target_link_dependencies(libdevilutionx_lighting PUBLIC
DevilutionX::SDL
fmt::fmt
magic_enum::magic_enum
tl
unordered_dense::unordered_dense
@@ -552,7 +547,6 @@ add_devilutionx_object_library(libdevilutionx_ini
utils/ini.cpp
)
target_link_dependencies(libdevilutionx_ini PUBLIC
fmt::fmt
tl
unordered_dense::unordered_dense
libdevilutionx_strings
@@ -566,7 +560,6 @@ target_include_directories(libdevilutionx_log INTERFACE
${PROJECT_SOURCE_DIR}/Source)
target_link_libraries(libdevilutionx_log INTERFACE
DevilutionX::SDL
fmt::fmt
)
target_sources(libdevilutionx_log INTERFACE $<TARGET_OBJECTS:libdevilutionx_strings>)
@@ -632,7 +625,6 @@ if(SUPPORTS_MPQ)
)
target_link_dependencies(libdevilutionx_mpq PUBLIC
DevilutionX::SDL
fmt::fmt
mpqfs::mpqfs
tl
libdevilutionx_file_util
@@ -655,7 +647,6 @@ add_devilutionx_object_library(libdevilutionx_options
)
target_link_dependencies(libdevilutionx_options PUBLIC
DevilutionX::SDL
fmt::fmt
magic_enum::magic_enum
tl
unordered_dense::unordered_dense
@@ -695,7 +686,6 @@ add_devilutionx_object_library(libdevilutionx_player
target_link_dependencies(libdevilutionx_player
PUBLIC
DevilutionX::SDL
fmt::fmt
magic_enum::magic_enum
sol2::sol2
tl
@@ -760,7 +750,6 @@ target_link_dependencies(libdevilutionx_text_render
PUBLIC
libdevilutionx_surface
PRIVATE
fmt::fmt
unordered_dense::unordered_dense
libdevilutionx_clx_render
libdevilutionx_game_mode
@@ -787,7 +776,6 @@ add_devilutionx_object_library(libdevilutionx_txtdata
data/value_reader.cpp
)
target_link_dependencies(libdevilutionx_txtdata PUBLIC
fmt::fmt
tl
libdevilutionx_assets
libdevilutionx_parse_int
@@ -808,7 +796,6 @@ if(NOSOUND)
)
target_link_dependencies(libdevilutionx_sound PUBLIC
DevilutionX::SDL
fmt::fmt
magic_enum::magic_enum
tl
unordered_dense::unordered_dense
@@ -835,7 +822,6 @@ else()
endif()
target_link_dependencies(libdevilutionx_sound PUBLIC
DevilutionX::SDL
fmt::fmt
magic_enum::magic_enum
tl
unordered_dense::unordered_dense
@@ -850,7 +836,6 @@ add_devilutionx_object_library(libdevilutionx_stores
)
target_link_dependencies(libdevilutionx_stores PUBLIC
DevilutionX::SDL
fmt::fmt
tl
libdevilutionx_clx_render
libdevilutionx_control
@@ -863,8 +848,7 @@ add_devilutionx_object_library(libdevilutionx_strings
utils/str_cat.cpp
utils/str_case.cpp
)
target_link_dependencies(libdevilutionx_strings PRIVATE
fmt::fmt)
target_link_dependencies(libdevilutionx_strings PRIVATE)
add_devilutionx_object_library(libdevilutionx_utils_console
utils/console.cpp
@@ -903,6 +887,11 @@ if(IOS)
list(APPEND libdevilutionx_SRCS platform/ios/ios_paths.m)
endif()
if(AMIGA AND NOT WARPOS)
# Works around a missing `__cmpdf2` in the hard-float libgcc multilib.
list(APPEND libdevilutionx_SRCS platform/amiga/cmpdf2.c)
endif()
if(NOT DISABLE_DEMOMODE)
list(APPEND libdevilutionx_SRCS engine/demomode.cpp)
endif()
@@ -969,7 +958,6 @@ add_devilutionx_object_library(libdevilutionx ${libdevilutionx_SRCS})
target_include_directories(libdevilutionx PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
target_link_dependencies(libdevilutionx PUBLIC
DevilutionX::SDL
fmt::fmt
libsmackerdec
${LUA_LIBRARIES}
magic_enum::magic_enum
+2 -4
View File
@@ -16,9 +16,6 @@
#include <SDL.h>
#endif
#include <fmt/core.h>
#include <fmt/format.h>
#include "DiabloUI/diabloui.h"
#include "DiabloUI/dialogs.h"
#include "DiabloUI/multi/selgame.h"
@@ -36,6 +33,7 @@
#include "pfile.h"
#include "tables/playerdat.hpp"
#include "utils/enum_traits.h"
#include "utils/format.hpp"
#include "utils/language.h"
#include "utils/sdl_geometry.h"
#include "utils/str_cat.hpp"
@@ -620,7 +618,7 @@ static void UiSelHeroDialog(
} else {
CopyUtf8(dialogTitle, _("Delete Single Player Hero"), sizeof(dialogTitle));
}
strcpy(dialogText, fmt::format(fmt::runtime(_("Are you sure you want to delete the character \"{:s}\"?")), selhero_heroInfo.name).c_str());
strcpy(dialogText, FormatRuntime(_("Are you sure you want to delete the character \"{:s}\"?"), selhero_heroInfo.name).c_str());
if (UiSelHeroYesNoDialog(dialogTitle, dialogText))
fnremove(&selhero_heroInfo);
+2 -4
View File
@@ -10,9 +10,6 @@
#include <SDL.h>
#endif
#include <fmt/core.h>
#include <fmt/format.h>
#include "DiabloUI/diabloui.h"
#include "DiabloUI/ui_flags.hpp"
#include "DiabloUI/ui_item.h"
@@ -20,6 +17,7 @@
#include "engine/render/text_render.hpp"
#include "multi.h"
#include "storm/storm_net.hpp"
#include "utils/format.hpp"
#include "utils/language.h"
#include "utils/ui_fwd.h"
#include "utils/utf8.hpp"
@@ -138,7 +136,7 @@ void SelconnFocus(size_t value)
break;
}
CopyUtf8(selconn_MaxPlayers, fmt::format(fmt::runtime(_("Players Supported: {:d}")), players), sizeof(selconn_MaxPlayers));
CopyUtf8(selconn_MaxPlayers, FormatRuntime(_("Players Supported: {:d}"), players), sizeof(selconn_MaxPlayers));
CopyUtf8(selconn_Description, WordWrapString(selconn_Description, DESCRIPTION_WIDTH), sizeof(selconn_Description));
}
+6 -8
View File
@@ -17,9 +17,6 @@
#include <SDL.h>
#endif
#include <fmt/core.h>
#include <fmt/format.h>
#include "DiabloUI/diabloui.h"
#include "DiabloUI/hero/selhero.h"
#include "DiabloUI/scrollbar.h"
@@ -35,6 +32,7 @@
#include "multi.h"
#include "options.h"
#include "storm/storm_net.hpp"
#include "utils/format.hpp"
#include "utils/language.h"
#include "utils/str_cat.hpp"
#include "utils/ui_fwd.h"
@@ -107,7 +105,7 @@ static std::string GetErrorMessageIncompatibility(const GameData &data)
else
return std::string(_("You need to full version of the game to join this game."));
}
return fmt::format(fmt::runtime(_(/* TRANSLATORS: Error message when somebody tries to join a game running another version. */ "Your version {:s} does not match the host {:d}.{:d}.{:d}.")), PROJECT_VERSION, data.versionMajor, data.versionMinor, data.versionPatch);
return FormatRuntime(_(/* TRANSLATORS: Error message when somebody tries to join a game running another version. */ "Your version {:s} does not match the host {:d}.{:d}.{:d}."), PROJECT_VERSION, data.versionMajor, data.versionMinor, data.versionPatch);
}
void UiInitGameSelectionList(std::string_view search)
@@ -248,7 +246,7 @@ void selgame_GameSelection_Focus(size_t value)
difficulty = _("Hell");
break;
}
infoString.append(fmt::format(fmt::runtime(_(/* TRANSLATORS: {:s} means: Game Difficulty. */ "Difficulty: {:s}")), difficulty));
infoString.append(FormatRuntime(_(/* TRANSLATORS: {:s} means: Game Difficulty. */ "Difficulty: {:s}"), difficulty));
infoString += '\n';
switch (gameInfo.gameData.nTickRate) {
case 20:
@@ -276,9 +274,9 @@ void selgame_GameSelection_Focus(size_t value)
}
infoString += '\n';
if (gameInfo.peerIsRelayed.value_or(false))
infoString.append(fmt::format(fmt::runtime(_("Ping: {:d} ms (RELAYED)")), gameInfo.latency.value_or(0)));
infoString.append(FormatRuntime(_("Ping: {:d} ms (RELAYED)"), gameInfo.latency.value_or(0)));
else
infoString.append(fmt::format(fmt::runtime(_("Ping: {:d} ms")), gameInfo.latency.value_or(0)));
infoString.append(FormatRuntime(_("Ping: {:d} ms"), gameInfo.latency.value_or(0)));
} else {
infoString.append(GetErrorMessageIncompatibility(gameInfo.gameData));
}
@@ -354,7 +352,7 @@ void selgame_GameSelection_Select(size_t value)
break;
}
case 2: {
selgame_Title = fmt::format(fmt::runtime(_("Join {:s} Games")), _(ConnectionNames[provider]));
selgame_Title = FormatRuntime(_("Join {:s} Games"), _(ConnectionNames[provider]));
title = selgame_Title.c_str();
const char *inputHint;
+6 -7
View File
@@ -18,12 +18,11 @@
#include "utils/sdl_compat.h"
#endif
#include <fmt/format.h>
#include "diablo.h"
#include "dvlnet/leaveinfo.hpp"
#include "multi.h"
#include "storm/storm_net.hpp"
#include "utils/format.hpp"
#include "utils/language.h"
#include "utils/sdl_thread.h"
#include "utils/str_cat.hpp"
@@ -83,16 +82,16 @@ void ErrDlg(const char *title, std::string_view error, std::string_view logFileP
{
DisplayFatalErrorAndExit(
title,
fmt::format(fmt::runtime(_(/* TRANSLATORS: Error message that displays relevant information for bug report */ "{:s}\n\nThe error occurred at: {:s} line {:d}")),
FormatRuntime(_(/* TRANSLATORS: Error message that displays relevant information for bug report */ "{:s}\n\nThe error occurred at: {:s} line {:d}"),
error, logFilePath, logLineNr));
}
void InsertCDDlg(std::string_view archiveName)
{
DisplayFatalErrorAndExit(_("Data File Error"),
fmt::format(fmt::runtime(_("Unable to open main data archive ({:s}).\n"
"\n"
"Make sure that it is in the game folder.")),
FormatRuntime(_("Unable to open main data archive ({:s}).\n"
"\n"
"Make sure that it is in the game folder."),
archiveName));
}
@@ -100,7 +99,7 @@ void DirErrorDlg(std::string_view error)
{
DisplayFatalErrorAndExit(
_("Read-Only Directory Error"),
fmt::format(fmt::runtime(_(/* TRANSLATORS: Error when Program is not allowed to write data */ "Unable to write to location:\n{:s}")),
FormatRuntime(_(/* TRANSLATORS: Error when Program is not allowed to write data */ "Unable to write to location:\n{:s}"),
error));
}
+5 -6
View File
@@ -8,8 +8,6 @@
#include <algorithm>
#include <cstdint>
#include <fmt/format.h>
#include "control/control.hpp"
#include "engine/load_file.hpp"
#include "engine/palette.h"
@@ -21,6 +19,7 @@
#include "player.h"
#include "utils/attributes.h"
#include "utils/enum_traits.h"
#include "utils/format.hpp"
#include "utils/is_of.hpp"
#include "utils/language.h"
#include "utils/ui_fwd.h"
@@ -1467,16 +1466,16 @@ void DrawAutomapText(const Surface &out)
std::string description;
switch (leveltype) {
case DTYPE_NEST:
description = fmt::format(fmt::runtime(_("Level: Nest {:d}")), currlevel - 16);
description = FormatRuntime(_("Level: Nest {:d}"), currlevel - 16);
break;
case DTYPE_CRYPT:
description = fmt::format(fmt::runtime(_("Level: Crypt {:d}")), currlevel - 20);
description = FormatRuntime(_("Level: Crypt {:d}"), currlevel - 20);
break;
case DTYPE_TOWN:
description = std::string(_("Town"));
break;
default:
description = fmt::format(fmt::runtime(_("Level: {:d}")), currlevel);
description = FormatRuntime(_("Level: {:d}"), currlevel);
break;
}
drawStringAndAdvanceLine(description);
@@ -1495,7 +1494,7 @@ void DrawAutomapText(const Surface &out)
break;
}
const std::string description = fmt::format(fmt::runtime(_(/* TRANSLATORS: {:s} means: Game Difficulty. */ "Difficulty: {:s}")), difficulty);
const std::string description = FormatRuntime(_(/* TRANSLATORS: {:s} means: Game Difficulty. */ "Difficulty: {:s}"), difficulty);
drawStringAndAdvanceLine(description);
#ifdef _DEBUG
+5 -6
View File
@@ -1,14 +1,13 @@
#include "control_chat_commands.hpp"
#include "control.hpp"
#include <fmt/format.h>
#include "diablo_msg.hpp"
#include "engine/backbuffer_state.hpp"
#include "inv.h"
#include "levels/setmaps.h"
#include "storm/storm_net.hpp"
#include "utils/algorithm/container.hpp"
#include "utils/format.hpp"
#include "utils/log.hpp"
#include "utils/parse_int.hpp"
#include "utils/str_case.hpp"
@@ -232,15 +231,15 @@ std::string TextCmdPing(const std::string_view parameter)
Player &player = *it;
DvlNetLatencies latencies = DvlNet_GetLatencies(player.getId());
StrAppend(ret, fmt::format(fmt::runtime(_(/* TRANSLATORS: {:s} means: Character Name */ "Latency statistics for {:s}:")), player.name()));
StrAppend(ret, FormatRuntime(_(/* TRANSLATORS: {:s} means: Character Name */ "Latency statistics for {:s}:"), player.name()));
StrAppend(ret, "\n", fmt::format(fmt::runtime(_(/* TRANSLATORS: Network connectivity statistics */ "Echo latency: {:d} ms")), latencies.echoLatency));
StrAppend(ret, "\n", FormatRuntime(_(/* TRANSLATORS: Network connectivity statistics */ "Echo latency: {:d} ms"), latencies.echoLatency));
if (latencies.providerLatency) {
if (latencies.isRelayed && *latencies.isRelayed) {
StrAppend(ret, "\n", fmt::format(fmt::runtime(_(/* TRANSLATORS: Network connectivity statistics */ "Provider latency: {:d} ms (Relayed)")), *latencies.providerLatency));
StrAppend(ret, "\n", FormatRuntime(_(/* TRANSLATORS: Network connectivity statistics */ "Provider latency: {:d} ms (Relayed)"), *latencies.providerLatency));
} else {
StrAppend(ret, "\n", fmt::format(fmt::runtime(_(/* TRANSLATORS: Network connectivity statistics */ "Provider latency: {:d} ms")), *latencies.providerLatency));
StrAppend(ret, "\n", FormatRuntime(_(/* TRANSLATORS: Network connectivity statistics */ "Provider latency: {:d} ms"), *latencies.providerLatency));
}
}
+4 -5
View File
@@ -1,12 +1,11 @@
#include "control.hpp"
#include "control_chat.hpp"
#include <fmt/format.h>
#include "DiabloUI/text_input.hpp"
#include "engine/render/clx_render.hpp"
#include "inv.h"
#include "utils/display.h"
#include "utils/format.hpp"
#include "utils/format_int.hpp"
#include "utils/log.hpp"
#include "utils/sdl_compat.h"
@@ -56,12 +55,12 @@ void DrawGoldSplit(const Surface &out)
const TextInputCursorState &cursor = GoldDropCursor;
const int max = GetGoldDropMax();
const std::string description = fmt::format(
fmt::runtime(ngettext(
const std::string description = FormatRuntime(
ngettext(
/* TRANSLATORS: {:s} is a number with separators. Dialog is shown when splitting a stash of Gold.*/
"You have {:s} gold piece. How many do you want to remove?",
"You have {:s} gold pieces. How many do you want to remove?",
max)),
max),
FormatInteger(max));
// Pre-wrap the string at spaces, otherwise DrawString would hard wrap in the middle of words
+13 -15
View File
@@ -1,8 +1,5 @@
#include "control.hpp"
#include "control_panel.hpp"
#include <fmt/format.h>
#include "controls/control_mode.hpp"
#include "engine/render/primitive_render.hpp"
#include "inv.h"
@@ -14,6 +11,7 @@
#include "qol/xpbar.h"
#include "towners.h"
#include "utils/algorithm/container.hpp"
#include "utils/format.hpp"
#include "utils/format_int.hpp"
#include "utils/log.hpp"
#include "utils/screen_reader.hpp"
@@ -330,7 +328,7 @@ void CheckPanelInfo()
InfoString = _("Player attack");
}
if (PanBtnHotKey[i] != nullptr) {
AddInfoBoxString(fmt::format(fmt::runtime(_("Hotkey: {:s}")), _(PanBtnHotKey[i])));
AddInfoBoxString(FormatRuntime(_("Hotkey: {:s}"), _(PanBtnHotKey[i])));
}
InfoColor = UiFlags::ColorWhite;
MainPanelFlag = true;
@@ -349,30 +347,30 @@ void CheckPanelInfo()
? GetOptions().Padmapper.InputNameForAction("DisplaySpells", true)
: GetOptions().Keymapper.KeyNameForAction("DisplaySpells");
if (!speedbookKeyName.empty()) {
AddInfoBoxString(fmt::format(fmt::runtime(_("Hotkey: '{:s}'")), speedbookKeyName));
AddInfoBoxString(FormatRuntime(_("Hotkey: '{:s}'"), speedbookKeyName));
}
const Player &myPlayer = *MyPlayer;
const SpellID spellId = myPlayer._pRSpell;
if (IsValidSpell(spellId)) {
switch (myPlayer._pRSplType) {
case SpellType::Skill:
AddInfoBoxString(fmt::format(fmt::runtime(_("{:s} Skill")), pgettext("spell", GetSpellData(spellId).sNameText)));
AddInfoBoxString(FormatRuntime(_("{:s} Skill"), pgettext("spell", GetSpellData(spellId).sNameText)));
break;
case SpellType::Spell: {
AddInfoBoxString(fmt::format(fmt::runtime(_("{:s} Spell")), pgettext("spell", GetSpellData(spellId).sNameText)));
AddInfoBoxString(FormatRuntime(_("{:s} Spell"), pgettext("spell", GetSpellData(spellId).sNameText)));
const int spellLevel = myPlayer.GetSpellLevel(spellId);
AddInfoBoxString(spellLevel == 0 ? _("Spell Level 0 - Unusable") : fmt::format(fmt::runtime(_("Spell Level {:d}")), spellLevel));
AddInfoBoxString(spellLevel == 0 ? _("Spell Level 0 - Unusable") : FormatRuntime(_("Spell Level {:d}"), spellLevel));
} break;
case SpellType::Scroll: {
AddInfoBoxString(fmt::format(fmt::runtime(_("Scroll of {:s}")), pgettext("spell", GetSpellData(spellId).sNameText)));
AddInfoBoxString(FormatRuntime(_("Scroll of {:s}"), pgettext("spell", GetSpellData(spellId).sNameText)));
const int scrollCount = c_count_if(InventoryAndBeltPlayerItemsRange { myPlayer }, [spellId](const Item &item) {
return item.isScrollOf(spellId);
});
AddInfoBoxString(fmt::format(fmt::runtime(ngettext("{:d} Scroll", "{:d} Scrolls", scrollCount)), scrollCount));
AddInfoBoxString(FormatRuntime(ngettext("{:d} Scroll", "{:d} Scrolls", scrollCount), scrollCount));
} break;
case SpellType::Charges:
AddInfoBoxString(fmt::format(fmt::runtime(_("Staff of {:s}")), pgettext("spell", GetSpellData(spellId).sNameText)));
AddInfoBoxString(fmt::format(fmt::runtime(ngettext("{:d} Charge", "{:d} Charges", myPlayer.InvBody[INVLOC_HAND_LEFT]._iCharges)), myPlayer.InvBody[INVLOC_HAND_LEFT]._iCharges));
AddInfoBoxString(FormatRuntime(_("Staff of {:s}"), pgettext("spell", GetSpellData(spellId).sNameText)));
AddInfoBoxString(FormatRuntime(ngettext("{:d} Charge", "{:d} Charges", myPlayer.InvBody[INVLOC_HAND_LEFT]._iCharges), myPlayer.InvBody[INVLOC_HAND_LEFT]._iCharges));
break;
case SpellType::Invalid:
break;
@@ -404,7 +402,7 @@ void DrawInfoBox(const Surface &out)
} else if (!myPlayer.HoldItem.isEmpty()) {
if (myPlayer.HoldItem._itype == ItemType::Gold) {
const int nGold = myPlayer.HoldItem._ivalue;
InfoString = fmt::format(fmt::runtime(ngettext("{:s} gold piece", "{:s} gold pieces", nGold)), FormatInteger(nGold));
InfoString = FormatRuntime(ngettext("{:s} gold piece", "{:s} gold pieces", nGold), FormatInteger(nGold));
} else if (!myPlayer.CanUseItem(myPlayer.HoldItem)) {
InfoString = _("Requirements not met");
} else {
@@ -435,8 +433,8 @@ void DrawInfoBox(const Surface &out)
InfoColor = UiFlags::ColorWhitegold;
const auto &target = *PlayerUnderCursor;
InfoString = std::string_view(target._pName);
AddInfoBoxString(fmt::format(fmt::runtime(_("{:s}, Level: {:d}")), target.getClassName(), target.getCharacterLevel()));
AddInfoBoxString(fmt::format(fmt::runtime(_("Hit Points {:d} of {:d}")), target._pHitPoints >> 6, target._pMaxHP >> 6));
AddInfoBoxString(FormatRuntime(_("{:s}, Level: {:d}"), target.getClassName(), target.getCharacterLevel()));
AddInfoBoxString(FormatRuntime(_("Hit Points {:d} of {:d}"), target._pHitPoints >> 6, target._pMaxHP >> 6));
}
if (PortraitIdUnderCursor != -1) {
InfoColor = UiFlags::ColorWhitegold;
+4 -5
View File
@@ -3,8 +3,6 @@
#include "control_chat.hpp"
#include "control_flasks.hpp"
#include <fmt/format.h>
#include "automap.h"
#include "controls/control_mode.hpp"
#include "controls/modifier_hints.h"
@@ -27,6 +25,7 @@
#include "qol/stash.h"
#include "qol/visual_store.h"
#include "stores.h"
#include "utils/format.hpp"
#include "utils/sdl_compat.h"
namespace devilution {
@@ -820,12 +819,12 @@ void DrawDeathText(const Surface &out)
if (!gbIsMultiplayer) {
if (gbValidSaveFile)
text = fmt::format(fmt::runtime(_("Press {} to load last save.")), buttonText);
text = FormatRuntime(_("Press {} to load last save."), buttonText);
else
text = fmt::format(fmt::runtime(_("Press {} to return to Main Menu.")), buttonText);
text = FormatRuntime(_("Press {} to return to Main Menu."), buttonText);
} else {
text = fmt::format(fmt::runtime(_("Press {} to restart in town.")), buttonText);
text = FormatRuntime(_("Press {} to restart in town."), buttonText);
}
DrawString(out, text, linePosition, smallTextOptions);
}
+2 -3
View File
@@ -18,8 +18,6 @@
#include <SDL.h>
#endif
#include <fmt/format.h>
#include "DiabloUI/diabloui.h"
#include "control/control.hpp"
#include "controls/control_mode.hpp"
@@ -44,6 +42,7 @@
#include "towners.h"
#include "track.h"
#include "utils/attributes.h"
#include "utils/format.hpp"
#include "utils/is_of.hpp"
#include "utils/language.h"
#include "utils/palette_blending.hpp"
@@ -628,7 +627,7 @@ void CheckTown()
if (EntranceBoundaryContains(missile.position.tile, cursPosition)) {
trigflag = true;
InfoString = _("Town Portal");
AddInfoBoxString(fmt::format(fmt::runtime(_("from {:s}")), Players[missile._misource]._pName));
AddInfoBoxString(FormatRuntime(_("from {:s}"), Players[missile._misource]._pName));
cursPosition = missile.position.tile;
}
}
+19 -20
View File
@@ -7,10 +7,9 @@
#include <limits>
#include <memory>
#include <fmt/format.h>
#include "engine/assets.hpp"
#include "utils/algorithm/container.hpp"
#include "utils/format.hpp"
#include "utils/language.h"
namespace devilution {
@@ -47,19 +46,19 @@ void DataFile::reportFatalError(Error code, std::string_view fileName)
case Error::NotFound:
case Error::OpenFailed:
case Error::BadRead:
app_fatal(fmt::format(fmt::runtime(_(
/* TRANSLATORS: Error message when a data file is missing or corrupt. Arguments are {file name} */
"Unable to load data from file {0}")),
app_fatal(FormatRuntime(_(
/* TRANSLATORS: Error message when a data file is missing or corrupt. Arguments are {file name} */
"Unable to load data from file {0}"),
fileName));
case Error::NoContent:
app_fatal(fmt::format(fmt::runtime(_(
/* TRANSLATORS: Error message when a data file is empty or only contains the header row. Arguments are {file name} */
"{0} is incomplete, please check the file contents.")),
app_fatal(FormatRuntime(_(
/* TRANSLATORS: Error message when a data file is empty or only contains the header row. Arguments are {file name} */
"{0} is incomplete, please check the file contents."),
fileName));
case Error::NotEnoughColumns:
app_fatal(fmt::format(fmt::runtime(_(
/* TRANSLATORS: Error message when a data file doesn't contain the expected columns. Arguments are {file name} */
"Your {0} file doesn't have the expected columns, please make sure it matches the documented format.")),
app_fatal(FormatRuntime(_(
/* TRANSLATORS: Error message when a data file doesn't contain the expected columns. Arguments are {file name} */
"Your {0} file doesn't have the expected columns, please make sure it matches the documented format."),
fileName));
}
}
@@ -72,21 +71,21 @@ void DataFile::reportFatalFieldError(DataFileField::Error code, std::string_view
}
switch (code) {
case DataFileField::Error::NotANumber:
app_fatal(fmt::format(fmt::runtime(_(
/* TRANSLATORS: Error message when parsing a data file and a text value is encountered when a number is expected. Arguments are {found value}, {column heading}, {file name}, {row/record number}, {column/field number} */
"Non-numeric value {0} for {1} in {2} at row {3} and column {4}")),
app_fatal(FormatRuntime(_(
/* TRANSLATORS: Error message when parsing a data file and a text value is encountered when a number is expected. Arguments are {found value}, {column heading}, {file name}, {row/record number}, {column/field number} */
"Non-numeric value {0} for {1} in {2} at row {3} and column {4}"),
field.currentValue(), fieldName, fileName, field.row(), field.column())
.append(detailsStr));
case DataFileField::Error::OutOfRange:
app_fatal(fmt::format(fmt::runtime(_(
/* TRANSLATORS: Error message when parsing a data file and we find a number larger than expected. Arguments are {found value}, {column heading}, {file name}, {row/record number}, {column/field number} */
"Out of range value {0} for {1} in {2} at row {3} and column {4}")),
app_fatal(FormatRuntime(_(
/* TRANSLATORS: Error message when parsing a data file and we find a number larger than expected. Arguments are {found value}, {column heading}, {file name}, {row/record number}, {column/field number} */
"Out of range value {0} for {1} in {2} at row {3} and column {4}"),
field.currentValue(), fieldName, fileName, field.row(), field.column())
.append(detailsStr));
case DataFileField::Error::InvalidValue:
app_fatal(fmt::format(fmt::runtime(_(
/* TRANSLATORS: Error message when we find an unrecognised value in a key column. Arguments are {found value}, {column heading}, {file name}, {row/record number}, {column/field number} */
"Invalid value {0} for {1} in {2} at row {3} and column {4}")),
app_fatal(FormatRuntime(_(
/* TRANSLATORS: Error message when we find an unrecognised value in a key column. Arguments are {found value}, {column heading}, {file name}, {row/record number}, {column/field number} */
"Invalid value {0} for {1} in {2} at row {3} and column {4}"),
field.currentValue(), fieldName, fileName, field.row(), field.column())
.append(detailsStr));
}
+3 -4
View File
@@ -1,7 +1,6 @@
#include "data/value_reader.hpp"
#include <fmt/core.h>
#include <fmt/format.h>
#include <format>
#include "appfat.h"
@@ -17,7 +16,7 @@ ValueReader::ValueReader(DataFile &dataFile, std::string_view filename)
DataFileField ValueReader::getValueField(std::string_view expectedKey)
{
if (it_ == end_) {
app_fatal(fmt::format("Missing field {} in {}", expectedKey, filename_));
app_fatal(std::format("Missing field {} in {}", expectedKey, filename_));
}
DataFileRecord record = *it_;
FieldIterator fieldIt = record.begin();
@@ -25,7 +24,7 @@ DataFileField ValueReader::getValueField(std::string_view expectedKey)
const std::string_view key = (*fieldIt).value();
if (key != expectedKey) {
app_fatal(fmt::format("Unexpected field in {}: got {}, expected {}", filename_, key, expectedKey));
app_fatal(std::format("Unexpected field in {}: got {}, expected {}", filename_, key, expectedKey));
}
++fieldIt;
+10 -11
View File
@@ -19,8 +19,6 @@
#endif
#endif
#include <fmt/format.h>
#include <config.h>
#include "DiabloUI/selstart.h"
@@ -108,6 +106,7 @@
#include "track.h"
#include "utils/console.h"
#include "utils/display.h"
#include "utils/format.hpp"
#include "utils/is_of.hpp"
#include "utils/language.h"
#include "utils/parse_int.hpp"
@@ -1587,17 +1586,17 @@ void TimeoutCursor(bool bTimeout)
DvlNetLatencies latencies = DvlNet_GetLatencies(i);
std::string ping = fmt::format(
fmt::runtime(_(/* TRANSLATORS: {:s} means: Character Name */ "Player {:s} is timing out!")),
std::string ping = FormatRuntime(
_(/* TRANSLATORS: {:s} means: Character Name */ "Player {:s} is timing out!"),
Players[i].name());
StrAppend(ping, "\n ", fmt::format(fmt::runtime(_(/* TRANSLATORS: Network connectivity statistics */ "Echo latency: {:d} ms")), latencies.echoLatency));
StrAppend(ping, "\n ", FormatRuntime(_(/* TRANSLATORS: Network connectivity statistics */ "Echo latency: {:d} ms"), latencies.echoLatency));
if (latencies.providerLatency) {
if (latencies.isRelayed && *latencies.isRelayed) {
StrAppend(ping, "\n ", fmt::format(fmt::runtime(_(/* TRANSLATORS: Network connectivity statistics */ "Provider latency: {:d} ms (Relayed)")), *latencies.providerLatency));
StrAppend(ping, "\n ", FormatRuntime(_(/* TRANSLATORS: Network connectivity statistics */ "Provider latency: {:d} ms (Relayed)"), *latencies.providerLatency));
} else {
StrAppend(ping, "\n ", fmt::format(fmt::runtime(_(/* TRANSLATORS: Network connectivity statistics */ "Provider latency: {:d} ms")), *latencies.providerLatency));
StrAppend(ping, "\n ", FormatRuntime(_(/* TRANSLATORS: Network connectivity statistics */ "Provider latency: {:d} ms"), *latencies.providerLatency));
}
}
EventPlrMsg(ping);
@@ -2117,8 +2116,8 @@ void InitKeymapActions()
N_("Displays game infos."),
'V',
[] {
EventPlrMsg(fmt::format(
fmt::runtime(_(/* TRANSLATORS: {:s} means: Project Name, Game Version. */ "{:s} {:s}")),
EventPlrMsg(FormatRuntime(
_(/* TRANSLATORS: {:s} means: Project Name, Game Version. */ "{:s} {:s}"),
PROJECT_NAME,
PROJECT_VERSION),
UiFlags::ColorWhite);
@@ -2629,8 +2628,8 @@ void InitPadmapActions()
N_("Displays game infos."),
ControllerButton_NONE,
[] {
EventPlrMsg(fmt::format(
fmt::runtime(_(/* TRANSLATORS: {:s} means: Project Name, Game Version. */ "{:s} {:s}")),
EventPlrMsg(FormatRuntime(
_(/* TRANSLATORS: {:s} means: Project Name, Game Version. */ "{:s} {:s}"),
PROJECT_NAME,
PROJECT_VERSION),
UiFlags::ColorWhite);
+4 -5
View File
@@ -14,8 +14,6 @@
#include <string>
#include <tuple>
#include <fmt/format.h>
#include "config.h"
#include "levels/gendung.h"
#include "levels/setmaps.h"
@@ -24,6 +22,7 @@
#include "panels/charpanel.hpp"
#include "player.h"
#include "tables/playerdat.hpp"
#include "utils/format.hpp"
#include "utils/language.h"
#include "utils/str_cat.hpp"
@@ -94,14 +93,14 @@ std::string GetLocationString()
else if (tracked_data.dungeonArea == DTYPE_CRYPT)
level -= 20;
return fmt::format(fmt::runtime(_(/* TRANSLATORS: dungeon type and floor number i.e. "Cathedral 3"*/ "{} {}")), dungeonStr, level);
return FormatRuntime(_(/* TRANSLATORS: dungeon type and floor number i.e. "Cathedral 3"*/ "{} {}"), dungeonStr, level);
}
return dungeonStr;
}
std::string GetCharacterString()
{
return fmt::format(fmt::runtime(_(/* TRANSLATORS: Discord character, i.e. "Lv 6 Warrior" */ "Lv {} {}")), tracked_data.playerLevel, MyPlayer->getClassName());
return FormatRuntime(_(/* TRANSLATORS: Discord character, i.e. "Lv 6 Warrior" */ "Lv {} {}"), tracked_data.playerLevel, MyPlayer->getClassName());
}
std::string GetDetailString()
@@ -113,7 +112,7 @@ std::string GetStateString()
{
constexpr std::array<const char *, 3> DifficultyStrs = { N_("Normal"), N_("Nightmare"), N_("Hell") };
const std::string_view difficultyStr = _(DifficultyStrs[sgGameInitInfo.nDifficulty]);
return fmt::format(fmt::runtime(_(/* TRANSLATORS: Discord state i.e. "Nightmare difficulty" */ "{} difficulty")), difficultyStr);
return FormatRuntime(_(/* TRANSLATORS: Discord state i.e. "Nightmare difficulty" */ "{} difficulty"), difficultyStr);
}
std::string GetTooltipString()
+2 -2
View File
@@ -2,6 +2,7 @@
#include <exception>
#include <expected>
#include <format>
#include <functional>
#include <memory>
#include <stdexcept>
@@ -15,7 +16,6 @@
#endif
#include <asio/connect.hpp>
#include <fmt/format.h>
#include "options.h"
#include "utils/language.h"
@@ -216,7 +216,7 @@ void tcp_client::HandleTcpErrorCode()
if (code == PacketError::ErrorCode::DecryptionFailed)
RaiseIoHandlerError(_("Server failed to decrypt your packet. Check if you typed the password correctly."));
else
RaiseIoHandlerError(fmt::format("Unknown error code received from server: {:#04x}", pktData[0]));
RaiseIoHandlerError(std::format("Unknown error code received from server: {:#04x}", pktData[0]));
}
std::expected<void, PacketError> tcp_client::send(packet &pkt)
-9
View File
@@ -3,15 +3,6 @@
#include <memory>
#include <string>
// This header must be included before any 3DS code
// because 3DS SDK defines a macro with the same name
// as an fmt template parameter in some versions of fmt.
// See https://github.com/fmtlib/fmt/issues/3632
//
// 3DS uses some custom ASIO code that transitively includes
// the 3DS SDK.
#include <fmt/core.h>
#include <asio/ts/buffer.hpp>
#include <asio/ts/internet.hpp>
#include <asio/ts/io_context.hpp>
-9
View File
@@ -5,15 +5,6 @@
#include <memory>
#include <string>
// This header must be included before any 3DS code
// because 3DS SDK defines a macro with the same name
// as an fmt template parameter in some versions of fmt.
// See https://github.com/fmtlib/fmt/issues/3632
//
// 3DS uses some custom ASIO code that transitively includes
// the 3DS SDK.
#include <fmt/core.h>
#include <asio/ts/buffer.hpp>
#include <asio/ts/internet.hpp>
#include <asio/ts/io_context.hpp>
+2 -3
View File
@@ -17,12 +17,11 @@
#include <SDL.h>
#endif
#include <fmt/format.h>
#include "appfat.h"
#include "game_mode.hpp"
#include "mods/mod_identity.h"
#include "utils/file_util.h"
#include "utils/format.hpp"
#include "utils/log.hpp"
#include "utils/paths.h"
#include "utils/sdl_compat.h"
@@ -358,7 +357,7 @@ std::expected<AssetData, std::string> LoadIntegralAsset(std::string_view path)
std::string FailedToOpenFileErrorMessage(std::string_view path, std::string_view error)
{
return fmt::format(fmt::runtime(_("Failed to open file:\n{:s}\n\n{:s}\n\nThe MPQ file(s) might be damaged. Please check the file integrity.")), path, error);
return FormatRuntime(_("Failed to open file:\n{:s}\n\n{:s}\n\nThe MPQ file(s) might be damaged. Please check the file integrity."), path, error);
}
namespace {
-2
View File
@@ -18,8 +18,6 @@
#include <SDL.h>
#endif
#include <fmt/format.h>
#include "appfat.h"
#include "game_mode.hpp"
#include "headless_mode.hpp"
+9 -4
View File
@@ -7,6 +7,7 @@
#include <algorithm>
#include <cstdint>
#include <format>
#include "engine/point.hpp"
#include "engine/render/blit_impl.hpp"
@@ -16,7 +17,6 @@
#include "utils/static_vector.hpp"
#ifdef DEBUG_CLX
#include <fmt/format.h>
#include "utils/str_cat.hpp"
#endif
@@ -564,15 +564,20 @@ std::string ClxDescribe(ClxSprite clx)
if (IsClxOpaque(control)) {
if (IsClxOpaqueFill(control)) {
const uint8_t length = GetClxOpaqueFillWidth(control);
out.append(fmt::format("Fill | {:>5} | {:>5} | {}\n", length, 2, src[1]));
out.append(std::format("Fill | {:>5} | {:>5} | {}\n", length, 2, src[1]));
++src;
} else {
const uint8_t length = GetClxOpaquePixelsWidth(control);
out.append(fmt::format("Pixels | {:>5} | {:>5} | {}\n", length, length + 1, fmt::join(src + 1, src + 1 + length, " ")));
std::string pixels;
for (const uint8_t *it = src + 1, *pixelsEnd = src + 1 + length; it != pixelsEnd; ++it) {
if (!pixels.empty()) pixels += ' ';
StrAppend(pixels, *it);
}
out.append(std::format("Pixels | {:>5} | {:>5} | {}\n", length, length + 1, pixels));
src += length;
}
} else {
out.append(fmt::format("Transp. | {:>5} | {:>5} |\n", control, 1));
out.append(std::format("Transp. | {:>5} | {:>5} |\n", control, 1));
}
}
return out;
+2 -3
View File
@@ -15,8 +15,6 @@
#include <variant>
#include <ankerl/unordered_dense.h>
#include <fmt/core.h>
#include <fmt/format.h>
#include "DiabloUI/ui_flags.hpp"
#include "engine/clx_sprite.hpp"
@@ -32,6 +30,7 @@
#include "engine/ticks.hpp"
#include "game_mode.hpp"
#include "utils/algorithm/container.hpp"
#include "utils/format.hpp"
#include "utils/is_of.hpp"
#include "utils/language.h"
#include "utils/log.hpp"
@@ -343,7 +342,7 @@ public:
} else {
if (!args_[*result].HasFormatted()) {
const auto fmtStr = positional ? "{}" : std::string_view(rest.data(), fmtLen);
args_[*result].SetFormatted(fmt::format(fmt::runtime(fmtStr), std::get<int>(args_[*result].value())));
args_[*result].SetFormatted(FormatRuntime(fmtStr, std::get<int>(args_[*result].value())));
}
rest.remove_prefix(fmtLen);
}
+2 -4
View File
@@ -14,8 +14,6 @@
#include <variant>
#include <vector>
#include <fmt/format.h>
#include "DiabloUI/ui_flags.hpp"
#include "engine/clx_sprite.hpp"
#include "engine/palette.h"
@@ -182,7 +180,7 @@ int GetLineWidth(std::string_view text, GameFontTables size = GameFont12, int sp
/**
* @brief Calculate pixel width of first line of text, respecting kerning
* @param fmt An fmt::format string.
* @param fmt A std::format string.
* @param args Format arguments.
* @param argsLen Number of format arguments.
* @param argsOffset Index of the first unprocessed format argument.
@@ -252,7 +250,7 @@ inline void DrawString(const Surface &out, std::string_view text, const Point &p
* DrawStringWithColors(out, "Press {} to start", {{"Ⓧ", UiFlags::ColorBlue}}, {.flags = UiFlags::ColorWhite})
*
* @param out Output buffer to draw the text on.
* @param fmt An fmt::format string.
* @param fmt A std::format string.
* @param args Format arguments.
* @param argsLen Number of format arguments.
* @param rect Clipping region relative to the output buffer describing where to draw the text and when to wrap long lines.
-2
View File
@@ -2,8 +2,6 @@
#include <cstdint>
#include <fmt/format.h>
#ifdef _DEBUG
#include "debug.h"
#endif
+3 -4
View File
@@ -16,8 +16,6 @@
#include <SDL.h>
#endif
#include <fmt/format.h>
#include "DiabloUI/ui_flags.hpp"
#include "controls/control_mode.hpp"
#include "controls/plrctrls.h"
@@ -43,6 +41,7 @@
#include "stores.h"
#include "towners.h"
#include "utils/display.h"
#include "utils/format.hpp"
#include "utils/format_int.hpp"
#include "utils/is_of.hpp"
#include "utils/language.h"
@@ -2002,8 +2001,8 @@ int8_t CheckInvHLight()
AddInfoBoxString(_("Fully Repaired"));
} else if (pi->_itype == ItemType::Gold) {
const int nGold = pi->_ivalue;
InfoString = fmt::format(fmt::runtime(ngettext("{:s} gold piece", "{:s} gold pieces", nGold)), FormatInteger(nGold));
FloatingInfoString = fmt::format(fmt::runtime(ngettext("{:s} gold piece", "{:s} gold pieces", nGold)), FormatInteger(nGold));
InfoString = FormatRuntime(ngettext("{:s} gold piece", "{:s} gold pieces", nGold), FormatInteger(nGold));
FloatingInfoString = FormatRuntime(ngettext("{:s} gold piece", "{:s} gold pieces", nGold), FormatInteger(nGold));
} else {
InfoColor = pi->getTextColor();
InfoString = pi->getName();
+77 -79
View File
@@ -25,9 +25,6 @@
#include <SDL.h>
#endif
#include <fmt/core.h>
#include <fmt/format.h>
#include "DiabloUI/ui_flags.hpp"
#include "control/control.hpp"
#include "controls/control_mode.hpp"
@@ -81,6 +78,7 @@
#include "tables/spelldat.h"
#include "tables/textdat.h"
#include "utils/enum_traits.h"
#include "utils/format.hpp"
#include "utils/format_int.hpp"
#include "utils/is_of.hpp"
#include "utils/language.h"
@@ -1108,10 +1106,10 @@ std::string GenerateStaffName(const ItemData &baseItemData, SpellID spellId, boo
std::string_view baseName = translate ? _(baseItemData.iName) : baseItemData.iName;
std::string_view spellName = translate ? pgettext("spell", GetSpellData(spellId).sNameText) : GetSpellData(spellId).sNameText;
const std::string_view normalFmt = translate ? pgettext("spell", /* TRANSLATORS: Constructs item names. Format: {Item} of {Spell}. Example: War Staff of Firewall */ "{0} of {1}") : "{0} of {1}";
std::string name = fmt::format(fmt::runtime(normalFmt), baseName, spellName);
std::string name = FormatRuntime(normalFmt, baseName, spellName);
if (!StringInPanel(name.c_str())) {
std::string_view shortName = translate ? _(baseItemData.iSName) : baseItemData.iSName;
name = fmt::format(fmt::runtime(normalFmt), shortName, spellName);
name = FormatRuntime(normalFmt, shortName, spellName);
}
return name;
}
@@ -1123,10 +1121,10 @@ std::string GenerateStaffNameMagical(const ItemData &baseItemData, SpellID spell
std::string_view spellName = translate ? pgettext("spell", GetSpellData(spellId).sNameText) : GetSpellData(spellId).sNameText;
std::string_view prefixName = translate ? _(power.PLName) : power.PLName;
std::string identifiedName = fmt::format(fmt::runtime(magicFmt), prefixName, baseName, spellName);
std::string identifiedName = FormatRuntime(magicFmt, prefixName, baseName, spellName);
if (forceNameLengthCheck ? *forceNameLengthCheck : !StringInPanel(identifiedName.c_str())) {
std::string_view shortName = translate ? _(baseItemData.iSName) : baseItemData.iSName;
identifiedName = fmt::format(fmt::runtime(magicFmt), prefixName, shortName, spellName);
identifiedName = FormatRuntime(magicFmt, prefixName, shortName, spellName);
}
return identifiedName;
}
@@ -1158,15 +1156,15 @@ std::string GenerateMagicItemName(const std::string_view &baseNamel, const PLStr
{
if (pPrefix != nullptr && pSufix != nullptr) {
const std::string_view fmt = translate ? _(/* TRANSLATORS: Constructs item names. Format: {Prefix} {Item} of {Suffix}. Example: King's Long Sword of the Whale */ "{0} {1} of {2}") : "{0} {1} of {2}";
return fmt::format(fmt::runtime(fmt), translate ? _(pPrefix->PLName) : pPrefix->PLName, baseNamel, translate ? _(pSufix->PLName) : pSufix->PLName);
return FormatRuntime(fmt, translate ? _(pPrefix->PLName) : pPrefix->PLName, baseNamel, translate ? _(pSufix->PLName) : pSufix->PLName);
}
if (pPrefix != nullptr) {
const std::string_view fmt = translate ? _(/* TRANSLATORS: Constructs item names. Format: {Prefix} {Item}. Example: King's Long Sword */ "{0} {1}") : "{0} {1}";
return fmt::format(fmt::runtime(fmt), translate ? _(pPrefix->PLName) : pPrefix->PLName, baseNamel);
return FormatRuntime(fmt, translate ? _(pPrefix->PLName) : pPrefix->PLName, baseNamel);
}
if (pSufix != nullptr) {
const std::string_view fmt = translate ? _(/* TRANSLATORS: Constructs item names. Format: {Item} of {Suffix}. Example: Long Sword of the Whale */ "{0} of {1}") : "{0} of {1}";
return fmt::format(fmt::runtime(fmt), baseNamel, translate ? _(pSufix->PLName) : pSufix->PLName);
return FormatRuntime(fmt, baseNamel, translate ? _(pSufix->PLName) : pSufix->PLName);
}
return std::string(baseNamel);
@@ -1801,25 +1799,25 @@ void printItemMiscGamepad(const Item &item, bool isOil, bool isCastOnTarget)
const std::string_view castButton = GetOptions().Padmapper.InputNameForAction("SpellAction");
if (item._iMiscId == IMISC_MAPOFDOOM) {
AddItemInfoBoxString(fmt::format(fmt::runtime(_("{} to view")), activateButton));
AddItemInfoBoxString(FormatRuntime(_("{} to view"), activateButton));
} else if (isOil) {
PrintItemOil(item._iMiscId);
if (!invflag) {
AddItemInfoBoxString(_("Open inventory to use"));
} else {
AddItemInfoBoxString(fmt::format(fmt::runtime(_("{} to use")), activateButton));
AddItemInfoBoxString(FormatRuntime(_("{} to use"), activateButton));
}
} else if (isCastOnTarget) {
AddItemInfoBoxString(fmt::format(fmt::runtime(_("Select from spell book,\nthen {} to read")), castButton));
AddItemInfoBoxString(FormatRuntime(_("Select from spell book,\nthen {} to read"), castButton));
} else if (IsAnyOf(item._iMiscId, IMISC_BOOK, IMISC_NOTE, IMISC_SCROLL, IMISC_SCROLLT)) {
AddItemInfoBoxString(fmt::format(fmt::runtime(_("{} to read")), activateButton));
AddItemInfoBoxString(FormatRuntime(_("{} to read"), activateButton));
}
}
void PrintItemMisc(const Item &item)
{
if (item._iMiscId == IMISC_EAR) {
AddItemInfoBoxString(fmt::format(fmt::runtime(pgettext("player", "Level: {:d}")), item._ivalue));
AddItemInfoBoxString(FormatRuntime(pgettext("player", "Level: {:d}"), item._ivalue));
return;
}
if (item._iMiscId == IMISC_AURIC) {
@@ -1858,11 +1856,11 @@ void PrintItemInfo(const Item &item)
if (str != 0 || mag != 0 || dex != 0) {
std::string text = std::string(_("Required:"));
if (str != 0)
text.append(fmt::format(fmt::runtime(_(" {:d} Str")), str));
text.append(FormatRuntime(_(" {:d} Str"), str));
if (mag != 0)
text.append(fmt::format(fmt::runtime(_(" {:d} Mag")), mag));
text.append(FormatRuntime(_(" {:d} Mag"), mag));
if (dex != 0)
text.append(fmt::format(fmt::runtime(_(" {:d} Dex")), dex));
text.append(FormatRuntime(_(" {:d} Dex"), dex));
AddItemInfoBoxString(text);
}
}
@@ -2218,10 +2216,10 @@ StringOrView GetTranslatedItemName(const Item &item)
}
if (item._iMiscId == IMISC_BOOK) {
const std::string_view spellName = pgettext("spell", GetSpellData(item._iSpell).sNameText);
return fmt::format(fmt::runtime(_(/* TRANSLATORS: {:s} will be a spell name */ "Book of {:s}")), spellName);
return FormatRuntime(_(/* TRANSLATORS: {:s} will be a spell name */ "Book of {:s}"), spellName);
}
if (item._iMiscId == IMISC_EAR) {
return fmt::format(fmt::runtime(_(/* TRANSLATORS: {:s} will be a Character Name */ "Ear of {:s}")), item._iIName);
return FormatRuntime(_(/* TRANSLATORS: {:s} will be a Character Name */ "Ear of {:s}"), item._iIName);
}
if (item._iMiscId > IMISC_OILFIRST && item._iMiscId < IMISC_OILLAST) {
for (size_t i = 0; i < 10; i++) {
@@ -3575,7 +3573,7 @@ void RecreateEar(Item &item, uint16_t ic, uint32_t iseed, uint8_t bCursval, std:
{
InitializeItem(item, IDI_EAR);
const std::string itemName = fmt::format(fmt::runtime("Ear of {:s}"), heroName);
const std::string itemName = FormatRuntime("Ear of {:s}", heroName);
CopyUtf8(item._iName, itemName, ItemNameLength);
CopyUtf8(item._iIName, heroName, ItemNameLength);
@@ -3827,7 +3825,7 @@ void GetItemStr(Item &item)
InfoColor = item.getTextColor();
} else {
const int nGold = item._ivalue;
InfoString = fmt::format(fmt::runtime(ngettext("{:s} gold piece", "{:s} gold pieces", nGold)), FormatInteger(nGold));
InfoString = FormatRuntime(ngettext("{:s} gold piece", "{:s} gold pieces", nGold), FormatInteger(nGold));
}
}
@@ -3893,87 +3891,87 @@ bool DoOil(Player &player, int cii)
switch (plidx) {
case IPL_TOHIT:
case IPL_TOHIT_CURSE:
return fmt::format(fmt::runtime(_("chance to hit: {:+d}%")), item._iPLToHit);
return FormatRuntime(_("chance to hit: {:+d}%"), item._iPLToHit);
case IPL_DAMP:
case IPL_DAMP_CURSE:
return fmt::format(fmt::runtime(_(/*xgettext:no-c-format*/ "{:+d}% damage")), item._iPLDam);
return FormatRuntime(_(/*xgettext:no-c-format*/ "{:+d}% damage"), item._iPLDam);
case IPL_TOHIT_DAMP:
case IPL_TOHIT_DAMP_CURSE:
return fmt::format(fmt::runtime(_("to hit: {:+d}%, {:+d}% damage")), item._iPLToHit, item._iPLDam);
return FormatRuntime(_("to hit: {:+d}%, {:+d}% damage"), item._iPLToHit, item._iPLDam);
case IPL_ACP:
case IPL_ACP_CURSE:
return fmt::format(fmt::runtime(_(/*xgettext:no-c-format*/ "{:+d}% armor")), item._iPLAC);
return FormatRuntime(_(/*xgettext:no-c-format*/ "{:+d}% armor"), item._iPLAC);
case IPL_SETAC:
case IPL_AC_CURSE:
return fmt::format(fmt::runtime(_("armor class: {:d}")), item._iAC);
return FormatRuntime(_("armor class: {:d}"), item._iAC);
case IPL_FIRERES:
case IPL_FIRERES_CURSE:
if (item._iPLFR < MaxResistance)
return fmt::format(fmt::runtime(_("Resist Fire: {:+d}%")), item._iPLFR);
return FormatRuntime(_("Resist Fire: {:+d}%"), item._iPLFR);
else
return fmt::format(fmt::runtime(_("Resist Fire: {:+d}% MAX")), MaxResistance);
return FormatRuntime(_("Resist Fire: {:+d}% MAX"), MaxResistance);
case IPL_LIGHTRES:
case IPL_LIGHTRES_CURSE:
if (item._iPLLR < MaxResistance)
return fmt::format(fmt::runtime(_("Resist Lightning: {:+d}%")), item._iPLLR);
return FormatRuntime(_("Resist Lightning: {:+d}%"), item._iPLLR);
else
return fmt::format(fmt::runtime(_("Resist Lightning: {:+d}% MAX")), MaxResistance);
return FormatRuntime(_("Resist Lightning: {:+d}% MAX"), MaxResistance);
case IPL_MAGICRES:
case IPL_MAGICRES_CURSE:
if (item._iPLMR < MaxResistance)
return fmt::format(fmt::runtime(_("Resist Magic: {:+d}%")), item._iPLMR);
return FormatRuntime(_("Resist Magic: {:+d}%"), item._iPLMR);
else
return fmt::format(fmt::runtime(_("Resist Magic: {:+d}% MAX")), MaxResistance);
return FormatRuntime(_("Resist Magic: {:+d}% MAX"), MaxResistance);
case IPL_ALLRES:
if (item._iPLFR < MaxResistance)
return fmt::format(fmt::runtime(_("Resist All: {:+d}%")), item._iPLFR);
return FormatRuntime(_("Resist All: {:+d}%"), item._iPLFR);
else
return fmt::format(fmt::runtime(_("Resist All: {:+d}% MAX")), MaxResistance);
return FormatRuntime(_("Resist All: {:+d}% MAX"), MaxResistance);
case IPL_SPLLVLADD:
if (item._iSplLvlAdd > 0)
return fmt::format(fmt::runtime(ngettext("spells are increased {:d} level", "spells are increased {:d} levels", item._iSplLvlAdd)), item._iSplLvlAdd);
return FormatRuntime(ngettext("spells are increased {:d} level", "spells are increased {:d} levels", item._iSplLvlAdd), item._iSplLvlAdd);
else if (item._iSplLvlAdd < 0)
return fmt::format(fmt::runtime(ngettext("spells are decreased {:d} level", "spells are decreased {:d} levels", -item._iSplLvlAdd)), -item._iSplLvlAdd);
return FormatRuntime(ngettext("spells are decreased {:d} level", "spells are decreased {:d} levels", -item._iSplLvlAdd), -item._iSplLvlAdd);
else
return _("spell levels unchanged (?)");
case IPL_CHARGES:
return _("Extra charges");
case IPL_SPELL:
return fmt::format(fmt::runtime(ngettext("{:d} {:s} charge", "{:d} {:s} charges", item._iMaxCharges)), item._iMaxCharges, pgettext("spell", GetSpellData(item._iSpell).sNameText));
return FormatRuntime(ngettext("{:d} {:s} charge", "{:d} {:s} charges", item._iMaxCharges), item._iMaxCharges, pgettext("spell", GetSpellData(item._iSpell).sNameText));
case IPL_FIREDAM:
if (item._iFMinDam == item._iFMaxDam)
return fmt::format(fmt::runtime(_("Fire hit damage: {:d}")), item._iFMinDam);
return FormatRuntime(_("Fire hit damage: {:d}"), item._iFMinDam);
else
return fmt::format(fmt::runtime(_("Fire hit damage: {:d}-{:d}")), item._iFMinDam, item._iFMaxDam);
return FormatRuntime(_("Fire hit damage: {:d}-{:d}"), item._iFMinDam, item._iFMaxDam);
case IPL_LIGHTDAM:
if (item._iLMinDam == item._iLMaxDam)
return fmt::format(fmt::runtime(_("Lightning hit damage: {:d}")), item._iLMinDam);
return FormatRuntime(_("Lightning hit damage: {:d}"), item._iLMinDam);
else
return fmt::format(fmt::runtime(_("Lightning hit damage: {:d}-{:d}")), item._iLMinDam, item._iLMaxDam);
return FormatRuntime(_("Lightning hit damage: {:d}-{:d}"), item._iLMinDam, item._iLMaxDam);
case IPL_STR:
case IPL_STR_CURSE:
return fmt::format(fmt::runtime(_("{:+d} to strength")), item._iPLStr);
return FormatRuntime(_("{:+d} to strength"), item._iPLStr);
case IPL_MAG:
case IPL_MAG_CURSE:
return fmt::format(fmt::runtime(_("{:+d} to magic")), item._iPLMag);
return FormatRuntime(_("{:+d} to magic"), item._iPLMag);
case IPL_DEX:
case IPL_DEX_CURSE:
return fmt::format(fmt::runtime(_("{:+d} to dexterity")), item._iPLDex);
return FormatRuntime(_("{:+d} to dexterity"), item._iPLDex);
case IPL_VIT:
case IPL_VIT_CURSE:
return fmt::format(fmt::runtime(_("{:+d} to vitality")), item._iPLVit);
return FormatRuntime(_("{:+d} to vitality"), item._iPLVit);
case IPL_ATTRIBS:
case IPL_ATTRIBS_CURSE:
return fmt::format(fmt::runtime(_("{:+d} to all attributes")), item._iPLStr);
return FormatRuntime(_("{:+d} to all attributes"), item._iPLStr);
case IPL_GETHIT_CURSE:
case IPL_GETHIT:
return fmt::format(fmt::runtime(_("{:+d} damage from enemies")), item._iPLGetHit);
return FormatRuntime(_("{:+d} damage from enemies"), item._iPLGetHit);
case IPL_LIFE:
case IPL_LIFE_CURSE:
return fmt::format(fmt::runtime(_("Hit Points: {:+d}")), item._iPLHP >> 6);
return FormatRuntime(_("Hit Points: {:+d}"), item._iPLHP >> 6);
case IPL_MANA:
case IPL_MANA_CURSE:
return fmt::format(fmt::runtime(_("Mana: {:+d}")), item._iPLMana >> 6);
return FormatRuntime(_("Mana: {:+d}"), item._iPLMana >> 6);
case IPL_DUR:
return _("high durability");
case IPL_DUR_CURSE:
@@ -3981,26 +3979,26 @@ bool DoOil(Player &player, int cii)
case IPL_INDESTRUCTIBLE:
return _("indestructible");
case IPL_LIGHT:
return fmt::format(fmt::runtime(_(/*xgettext:no-c-format*/ "+{:d}% light radius")), 10 * item._iPLLight);
return FormatRuntime(_(/*xgettext:no-c-format*/ "+{:d}% light radius"), 10 * item._iPLLight);
case IPL_LIGHT_CURSE:
return fmt::format(fmt::runtime(_(/*xgettext:no-c-format*/ "-{:d}% light radius")), -10 * item._iPLLight);
return FormatRuntime(_(/*xgettext:no-c-format*/ "-{:d}% light radius"), -10 * item._iPLLight);
case IPL_MULT_ARROWS:
return _("multiple arrows per shot");
case IPL_FIRE_ARROWS:
if (item._iFMinDam == item._iFMaxDam)
return fmt::format(fmt::runtime(_("fire arrows damage: {:d}")), item._iFMinDam);
return FormatRuntime(_("fire arrows damage: {:d}"), item._iFMinDam);
else
return fmt::format(fmt::runtime(_("fire arrows damage: {:d}-{:d}")), item._iFMinDam, item._iFMaxDam);
return FormatRuntime(_("fire arrows damage: {:d}-{:d}"), item._iFMinDam, item._iFMaxDam);
case IPL_LIGHT_ARROWS:
if (item._iLMinDam == item._iLMaxDam)
return fmt::format(fmt::runtime(_("lightning arrows damage {:d}")), item._iLMinDam);
return FormatRuntime(_("lightning arrows damage {:d}"), item._iLMinDam);
else
return fmt::format(fmt::runtime(_("lightning arrows damage {:d}-{:d}")), item._iLMinDam, item._iLMaxDam);
return FormatRuntime(_("lightning arrows damage {:d}-{:d}"), item._iLMinDam, item._iLMaxDam);
case IPL_FIREBALL:
if (item._iFMinDam == item._iFMaxDam)
return fmt::format(fmt::runtime(_("fireball damage: {:d}")), item._iFMinDam);
return FormatRuntime(_("fireball damage: {:d}"), item._iFMinDam);
else
return fmt::format(fmt::runtime(_("fireball damage: {:d}-{:d}")), item._iFMinDam, item._iFMaxDam);
return FormatRuntime(_("fireball damage: {:d}-{:d}"), item._iFMinDam, item._iFMaxDam);
case IPL_THORNS:
return _("attacker takes 1-3 damage");
case IPL_NOMANA:
@@ -4048,7 +4046,7 @@ bool DoOil(Player &player, int cii)
case IPL_FASTBLOCK:
return _("fast block");
case IPL_DAMMOD:
return fmt::format(fmt::runtime(ngettext("adds {:d} point to damage", "adds {:d} points to damage", item._iPLDamMod)), item._iPLDamMod);
return FormatRuntime(ngettext("adds {:d} point to damage", "adds {:d} points to damage", item._iPLDamMod), item._iPLDamMod);
case IPL_RNDARROWVEL:
return _("fires random speed arrows");
case IPL_SETDAM:
@@ -4065,23 +4063,23 @@ bool DoOil(Player &player, int cii)
return _("no strength requirement");
case IPL_ADDACLIFE:
if (item._iFMinDam == item._iFMaxDam)
return fmt::format(fmt::runtime(_("lightning damage: {:d}")), item._iFMinDam);
return FormatRuntime(_("lightning damage: {:d}"), item._iFMinDam);
else
return fmt::format(fmt::runtime(_("lightning damage: {:d}-{:d}")), item._iFMinDam, item._iFMaxDam);
return FormatRuntime(_("lightning damage: {:d}-{:d}"), item._iFMinDam, item._iFMaxDam);
case IPL_ADDMANAAC:
return _("charged bolts on hits");
case IPL_DEVASTATION:
return _("occasional triple damage");
case IPL_DECAY:
return fmt::format(fmt::runtime(_(/*xgettext:no-c-format*/ "decaying {:+d}% damage")), item._iPLDam);
return FormatRuntime(_(/*xgettext:no-c-format*/ "decaying {:+d}% damage"), item._iPLDam);
case IPL_PERIL:
return _("2x dmg to monst, 1x to you");
case IPL_JESTERS:
return std::string(_(/*xgettext:no-c-format*/ "Random 0 - 600% damage"));
case IPL_CRYSTALLINE:
return fmt::format(fmt::runtime(_(/*xgettext:no-c-format*/ "low dur, {:+d}% damage")), item._iPLDam);
return FormatRuntime(_(/*xgettext:no-c-format*/ "low dur, {:+d}% damage"), item._iPLDam);
case IPL_DOPPELGANGER:
return fmt::format(fmt::runtime(_("to hit: {:+d}%, {:+d}% damage")), item._iPLToHit, item._iPLDam);
return FormatRuntime(_("to hit: {:+d}%, {:+d}% damage"), item._iPLToHit, item._iPLDam);
case IPL_ACDEMON:
return _("extra AC vs demons");
case IPL_ACUNDEAD:
@@ -4132,24 +4130,24 @@ void PrintItemDetails(const Item &item)
if (item._iClass == ICLASS_WEAPON) {
if (item._iMinDam == item._iMaxDam) {
if (item._iMaxDur == DUR_INDESTRUCTIBLE)
AddItemInfoBoxString(fmt::format(fmt::runtime(_("damage: {:d} Indestructible")), item._iMinDam));
AddItemInfoBoxString(FormatRuntime(_("damage: {:d} Indestructible"), item._iMinDam));
else
AddItemInfoBoxString(fmt::format(fmt::runtime(_(/* TRANSLATORS: Dur: is durability */ "damage: {:d} Dur: {:d}/{:d}")), item._iMinDam, item._iDurability, item._iMaxDur));
AddItemInfoBoxString(FormatRuntime(_(/* TRANSLATORS: Dur: is durability */ "damage: {:d} Dur: {:d}/{:d}"), item._iMinDam, item._iDurability, item._iMaxDur));
} else {
if (item._iMaxDur == DUR_INDESTRUCTIBLE)
AddItemInfoBoxString(fmt::format(fmt::runtime(_("damage: {:d}-{:d} Indestructible")), item._iMinDam, item._iMaxDam));
AddItemInfoBoxString(FormatRuntime(_("damage: {:d}-{:d} Indestructible"), item._iMinDam, item._iMaxDam));
else
AddItemInfoBoxString(fmt::format(fmt::runtime(_(/* TRANSLATORS: Dur: is durability */ "damage: {:d}-{:d} Dur: {:d}/{:d}")), item._iMinDam, item._iMaxDam, item._iDurability, item._iMaxDur));
AddItemInfoBoxString(FormatRuntime(_(/* TRANSLATORS: Dur: is durability */ "damage: {:d}-{:d} Dur: {:d}/{:d}"), item._iMinDam, item._iMaxDam, item._iDurability, item._iMaxDur));
}
}
if (item._iClass == ICLASS_ARMOR) {
if (item._iMaxDur == DUR_INDESTRUCTIBLE)
AddItemInfoBoxString(fmt::format(fmt::runtime(_("armor: {:d} Indestructible")), item._iAC));
AddItemInfoBoxString(FormatRuntime(_("armor: {:d} Indestructible"), item._iAC));
else
AddItemInfoBoxString(fmt::format(fmt::runtime(_(/* TRANSLATORS: Dur: is durability */ "armor: {:d} Dur: {:d}/{:d}")), item._iAC, item._iDurability, item._iMaxDur));
AddItemInfoBoxString(FormatRuntime(_(/* TRANSLATORS: Dur: is durability */ "armor: {:d} Dur: {:d}/{:d}"), item._iAC, item._iDurability, item._iMaxDur));
}
if (item._iMiscId == IMISC_STAFF && item._iMaxCharges != 0) {
AddItemInfoBoxString(fmt::format(fmt::runtime(_("Charges: {:d}/{:d}")), item._iCharges, item._iMaxCharges));
AddItemInfoBoxString(FormatRuntime(_("Charges: {:d}/{:d}"), item._iCharges, item._iMaxCharges));
}
if (item._iPrePower != -1) {
AddItemInfoBoxString(PrintItemPower(item._iPrePower, item));
@@ -4173,30 +4171,30 @@ void PrintItemDur(const Item &item)
if (item._iClass == ICLASS_WEAPON) {
if (item._iMinDam == item._iMaxDam) {
if (item._iMaxDur == DUR_INDESTRUCTIBLE)
AddItemInfoBoxString(fmt::format(fmt::runtime(_("damage: {:d} Indestructible")), item._iMinDam));
AddItemInfoBoxString(FormatRuntime(_("damage: {:d} Indestructible"), item._iMinDam));
else
AddItemInfoBoxString(fmt::format(fmt::runtime(_("damage: {:d} Dur: {:d}/{:d}")), item._iMinDam, item._iDurability, item._iMaxDur));
AddItemInfoBoxString(FormatRuntime(_("damage: {:d} Dur: {:d}/{:d}"), item._iMinDam, item._iDurability, item._iMaxDur));
} else {
if (item._iMaxDur == DUR_INDESTRUCTIBLE)
AddItemInfoBoxString(fmt::format(fmt::runtime(_("damage: {:d}-{:d} Indestructible")), item._iMinDam, item._iMaxDam));
AddItemInfoBoxString(FormatRuntime(_("damage: {:d}-{:d} Indestructible"), item._iMinDam, item._iMaxDam));
else
AddItemInfoBoxString(fmt::format(fmt::runtime(_("damage: {:d}-{:d} Dur: {:d}/{:d}")), item._iMinDam, item._iMaxDam, item._iDurability, item._iMaxDur));
AddItemInfoBoxString(FormatRuntime(_("damage: {:d}-{:d} Dur: {:d}/{:d}"), item._iMinDam, item._iMaxDam, item._iDurability, item._iMaxDur));
}
if (item._iMiscId == IMISC_STAFF && item._iMaxCharges > 0) {
AddItemInfoBoxString(fmt::format(fmt::runtime(_("Charges: {:d}/{:d}")), item._iCharges, item._iMaxCharges));
AddItemInfoBoxString(FormatRuntime(_("Charges: {:d}/{:d}"), item._iCharges, item._iMaxCharges));
}
if (item._iMagical != ITEM_QUALITY_NORMAL)
AddItemInfoBoxString(_("Not Identified"));
}
if (item._iClass == ICLASS_ARMOR) {
if (item._iMaxDur == DUR_INDESTRUCTIBLE)
AddItemInfoBoxString(fmt::format(fmt::runtime(_("armor: {:d} Indestructible")), item._iAC));
AddItemInfoBoxString(FormatRuntime(_("armor: {:d} Indestructible"), item._iAC));
else
AddItemInfoBoxString(fmt::format(fmt::runtime(_("armor: {:d} Dur: {:d}/{:d}")), item._iAC, item._iDurability, item._iMaxDur));
AddItemInfoBoxString(FormatRuntime(_("armor: {:d} Dur: {:d}/{:d}"), item._iAC, item._iDurability, item._iMaxDur));
if (item._iMagical != ITEM_QUALITY_NORMAL)
AddItemInfoBoxString(_("Not Identified"));
if (item._iMiscId == IMISC_STAFF && item._iMaxCharges > 0) {
AddItemInfoBoxString(fmt::format(fmt::runtime(_("Charges: {:d}/{:d}")), item._iCharges, item._iMaxCharges));
AddItemInfoBoxString(FormatRuntime(_("Charges: {:d}/{:d}"), item._iCharges, item._iMaxCharges));
}
}
if (IsAnyOf(item._itype, ItemType::Ring, ItemType::Amulet))
-2
View File
@@ -7,8 +7,6 @@
#include <cstdint>
#include <fmt/core.h>
#include "engine/path.h"
#include "engine/points_in_rectangle_range.hpp"
#include "engine/random.hpp"
+16 -17
View File
@@ -8,8 +8,6 @@
#include <cmath>
#include <cstdint>
#include <fmt/format.h>
#include "control/control.hpp"
#include "controls/control_mode.hpp"
#include "controls/plrctrls.h"
@@ -18,6 +16,7 @@
#include "game_mode.hpp"
#include "multi.h"
#include "utils/algorithm/container.hpp"
#include "utils/format.hpp"
#include "utils/is_of.hpp"
#include "utils/language.h"
#include "utils/utf8.hpp"
@@ -416,7 +415,7 @@ bool ForceL1Trig()
for (const uint16_t tileId : L1UpList) {
if (dPiece[cursPosition.x][cursPosition.y] == tileId) {
if (currlevel > 1)
InfoString = fmt::format(fmt::runtime(_("Up to level {:d}")), currlevel - 1);
InfoString = FormatRuntime(_("Up to level {:d}"), currlevel - 1);
else
InfoString = _("Up to town");
for (int j = 0; j < numtrigs; j++) {
@@ -429,7 +428,7 @@ bool ForceL1Trig()
}
for (const uint16_t tileId : L1DownList) {
if (dPiece[cursPosition.x][cursPosition.y] == tileId) {
InfoString = fmt::format(fmt::runtime(_("Down to level {:d}")), currlevel + 1);
InfoString = FormatRuntime(_("Down to level {:d}"), currlevel + 1);
for (int j = 0; j < numtrigs; j++) {
if (trigs[j]._tmsg == WM_DIABNEXTLVL) {
cursPosition = trigs[j].position;
@@ -451,7 +450,7 @@ bool ForceL2Trig()
const int dx = std::abs(trigs[j].position.x - cursPosition.x);
const int dy = std::abs(trigs[j].position.y - cursPosition.y);
if (dx < 4 && dy < 4) {
InfoString = fmt::format(fmt::runtime(_("Up to level {:d}")), currlevel - 1);
InfoString = FormatRuntime(_("Up to level {:d}"), currlevel - 1);
cursPosition = trigs[j].position;
return true;
}
@@ -462,7 +461,7 @@ bool ForceL2Trig()
for (const uint16_t tileId : L2DownList) {
if (dPiece[cursPosition.x][cursPosition.y] == tileId) {
InfoString = fmt::format(fmt::runtime(_("Down to level {:d}")), currlevel + 1);
InfoString = FormatRuntime(_("Down to level {:d}"), currlevel + 1);
for (int j = 0; j < numtrigs; j++) {
if (trigs[j]._tmsg == WM_DIABNEXTLVL) {
cursPosition = trigs[j].position;
@@ -497,7 +496,7 @@ bool ForceL3Trig()
{
for (const uint16_t tileId : L3UpList) {
if (dPiece[cursPosition.x][cursPosition.y] == tileId) {
InfoString = fmt::format(fmt::runtime(_("Up to level {:d}")), currlevel - 1);
InfoString = FormatRuntime(_("Up to level {:d}"), currlevel - 1);
for (int j = 0; j < numtrigs; j++) {
if (trigs[j]._tmsg == WM_DIABPREVLVL) {
const int dx = std::abs(trigs[j].position.x - cursPosition.x);
@@ -514,7 +513,7 @@ bool ForceL3Trig()
if (dPiece[cursPosition.x][cursPosition.y] == tileId
|| dPiece[cursPosition.x + 1][cursPosition.y] == tileId
|| dPiece[cursPosition.x + 2][cursPosition.y] == tileId) {
InfoString = fmt::format(fmt::runtime(_("Down to level {:d}")), currlevel + 1);
InfoString = FormatRuntime(_("Down to level {:d}"), currlevel + 1);
for (int j = 0; j < numtrigs; j++) {
if (trigs[j]._tmsg == WM_DIABNEXTLVL) {
cursPosition = trigs[j].position;
@@ -549,7 +548,7 @@ bool ForceL4Trig()
{
for (const uint16_t tileId : L4UpList) {
if (dPiece[cursPosition.x][cursPosition.y] == tileId) {
InfoString = fmt::format(fmt::runtime(_("Up to level {:d}")), currlevel - 1);
InfoString = FormatRuntime(_("Up to level {:d}"), currlevel - 1);
for (int j = 0; j < numtrigs; j++) {
if (trigs[j]._tmsg == WM_DIABPREVLVL) {
cursPosition = trigs[j].position;
@@ -561,7 +560,7 @@ bool ForceL4Trig()
for (const uint16_t tileId : L4DownList) {
if (dPiece[cursPosition.x][cursPosition.y] == tileId) {
InfoString = fmt::format(fmt::runtime(_("Down to level {:d}")), currlevel + 1);
InfoString = FormatRuntime(_("Down to level {:d}"), currlevel + 1);
for (int j = 0; j < numtrigs; j++) {
if (trigs[j]._tmsg == WM_DIABNEXTLVL) {
cursPosition = trigs[j].position;
@@ -610,7 +609,7 @@ bool ForceHiveTrig()
{
for (const uint16_t tileId : L6UpList) {
if (dPiece[cursPosition.x][cursPosition.y] == tileId) {
InfoString = fmt::format(fmt::runtime(_("Up to Nest level {:d}")), currlevel - 17);
InfoString = FormatRuntime(_("Up to Nest level {:d}"), currlevel - 17);
for (int j = 0; j < numtrigs; j++) {
if (trigs[j]._tmsg == WM_DIABPREVLVL) {
cursPosition = trigs[j].position;
@@ -623,7 +622,7 @@ bool ForceHiveTrig()
if (dPiece[cursPosition.x][cursPosition.y] == tileId
|| dPiece[cursPosition.x + 1][cursPosition.y] == tileId
|| dPiece[cursPosition.x + 2][cursPosition.y] == tileId) {
InfoString = fmt::format(fmt::runtime(_("Down to level {:d}")), currlevel - 15);
InfoString = FormatRuntime(_("Down to level {:d}"), currlevel - 15);
for (int j = 0; j < numtrigs; j++) {
if (trigs[j]._tmsg == WM_DIABNEXTLVL) {
cursPosition = trigs[j].position;
@@ -658,7 +657,7 @@ bool ForceCryptTrig()
{
for (const uint16_t tileId : L5UpList) {
if (dPiece[cursPosition.x][cursPosition.y] == tileId) {
InfoString = fmt::format(fmt::runtime(_("Up to Crypt level {:d}")), currlevel - 21);
InfoString = FormatRuntime(_("Up to Crypt level {:d}"), currlevel - 21);
for (int j = 0; j < numtrigs; j++) {
if (trigs[j]._tmsg == WM_DIABPREVLVL) {
cursPosition = trigs[j].position;
@@ -673,7 +672,7 @@ bool ForceCryptTrig()
}
for (const uint16_t tileId : L5DownList) {
if (dPiece[cursPosition.x][cursPosition.y] == tileId) {
InfoString = fmt::format(fmt::runtime(_("Down to Crypt level {:d}")), currlevel - 19);
InfoString = FormatRuntime(_("Down to Crypt level {:d}"), currlevel - 19);
for (int j = 0; j < numtrigs; j++) {
if (trigs[j]._tmsg == WM_DIABNEXTLVL) {
cursPosition = trigs[j].position;
@@ -721,7 +720,7 @@ bool ForceSKingTrig()
{
for (const uint16_t tileId : L1UpList) {
if (dPiece[cursPosition.x][cursPosition.y] == tileId) {
InfoString = fmt::format(fmt::runtime(_("Back to Level {:d}")), Quests[Q_SKELKING]._qlevel);
InfoString = FormatRuntime(_("Back to Level {:d}"), Quests[Q_SKELKING]._qlevel);
cursPosition = trigs[0].position;
return true;
@@ -735,7 +734,7 @@ bool ForceSChambTrig()
{
for (const uint16_t tileId : L2DownList) {
if (dPiece[cursPosition.x][cursPosition.y] == tileId) {
InfoString = fmt::format(fmt::runtime(_("Back to Level {:d}")), Quests[Q_SCHAMB]._qlevel);
InfoString = FormatRuntime(_("Back to Level {:d}"), Quests[Q_SCHAMB]._qlevel);
cursPosition = trigs[0].position;
return true;
@@ -749,7 +748,7 @@ bool ForcePWaterTrig()
{
for (const uint16_t tileId : L3DownList) {
if (dPiece[cursPosition.x][cursPosition.y] == tileId) {
InfoString = fmt::format(fmt::runtime(_("Back to Level {:d}")), Quests[Q_PWATER]._qlevel);
InfoString = FormatRuntime(_("Back to Level {:d}"), Quests[Q_PWATER]._qlevel);
cursPosition = trigs[0].position;
return true;
+2 -2
View File
@@ -2,10 +2,10 @@
#include <string_view>
#include <fmt/format.h>
#include <sol/sol.hpp>
#include "lua/metadoc.hpp"
#include "utils/format.hpp"
#include "utils/language.h"
namespace devilution {
@@ -19,7 +19,7 @@ sol::table LuaI18nModule(sol::state_view &lua)
"Translates the given string", [](const char *key) { return LanguageTranslate(key); });
LuaSetDocFn(table, "plural_translate", "(singular: string, plural: string, count: integer)",
"Returns a singular or plural translation for the given keys and count", [](const char *singular, std::string_view plural, int count) {
return fmt::format(fmt::runtime(LanguagePluralTranslate(singular, plural, count)), count);
return FormatRuntime(LanguagePluralTranslate(singular, plural, count), count);
});
LuaSetDocFn(table, "particular_translate", "(context: string, text: string)",
"Returns the translation for the given context identifier and key.", LanguageParticularTranslate);
-1
View File
@@ -2,7 +2,6 @@
#include <string_view>
#include <fmt/format.h>
#include <sol/sol.hpp>
#include "data/file.hpp"
+112 -38
View File
@@ -6,12 +6,23 @@
#include <SDL.h>
#endif
#include <fmt/args.h>
#include <fmt/format.h>
#include <charconv>
#include <cstddef>
#include <expected>
#include <format>
#include <span>
#include <string>
#include <string_view>
#include <system_error>
#include <variant>
#include <vector>
#include <sol/sol.hpp>
#include <sol/utility/to_string.hpp>
#include "utils/attributes.h"
#include "utils/log.hpp"
#include "utils/str_cat.hpp"
#ifdef USE_SDL1
#include "utils/sdl2_to_1_2_backports.h"
@@ -21,50 +32,113 @@ namespace devilution {
namespace {
using LuaFormatArg = std::variant<bool, lua_Integer, lua_Number, std::string>;
/**
* @brief Formats a message with arguments only known at runtime.
*
* `std::format` has no equivalent of `fmt::dynamic_format_arg_store`, so we
* parse the replacement fields ourselves and format each one individually.
*/
std::expected<std::string, std::string> FormatLuaMessage(std::string_view fmt, std::span<const LuaFormatArg> args)
{
std::string result;
result.reserve(fmt.size());
size_t autoIndex = 0;
bool manualIndexing = false;
bool automaticIndexing = false;
for (size_t i = 0; i < fmt.size(); ++i) {
const char c = fmt[i];
if (c == '}') {
if (i + 1 < fmt.size() && fmt[i + 1] == '}') {
result += '}';
++i;
continue;
}
return std::unexpected("unmatched '}' in format string");
}
if (c != '{') {
result += c;
continue;
}
if (i + 1 < fmt.size() && fmt[i + 1] == '{') {
result += '{';
++i;
continue;
}
const size_t fieldEnd = fmt.find_first_of("{}", i + 1);
if (fieldEnd == std::string_view::npos || fmt[fieldEnd] == '{')
return std::unexpected("unmatched '{' in format string");
const std::string_view field = fmt.substr(i + 1, fieldEnd - (i + 1));
const size_t colonPos = field.find(':');
const std::string_view argId = field.substr(0, colonPos);
size_t argIndex;
if (argId.empty()) {
if (manualIndexing)
return std::unexpected("cannot switch from manual to automatic argument indexing");
automaticIndexing = true;
argIndex = autoIndex++;
} else {
if (automaticIndexing)
return std::unexpected("cannot switch from automatic to manual argument indexing");
manualIndexing = true;
const std::from_chars_result parseResult = std::from_chars(argId.data(), argId.data() + argId.size(), argIndex);
if (parseResult.ec != std::errc() || parseResult.ptr != argId.data() + argId.size())
return std::unexpected(StrCat("invalid argument id \"", argId, "\""));
}
if (argIndex >= args.size())
return std::unexpected(StrCat("argument index ", argIndex, " out of range"));
const std::string fieldFmt = colonPos == std::string_view::npos
? "{}"
: StrCat("{:", field.substr(colonPos + 1), "}");
#if DVL_EXCEPTIONS
try {
#endif
std::visit([&](const auto &value) {
result += std::vformat(fieldFmt, std::make_format_args(value));
},
args[argIndex]);
#if DVL_EXCEPTIONS
} catch (const std::format_error &e) {
return std::unexpected(e.what());
}
#endif
i = fieldEnd;
}
return result;
}
void LuaLogMessage(LogPriority priority, std::string_view fmt, sol::variadic_args args)
{
std::string formatted;
FMT_TRY
{
fmt::dynamic_format_arg_store<fmt::format_context> store;
for (const sol::stack_proxy arg : args) {
switch (arg.get_type()) {
case sol::type::boolean:
store.push_back(arg.as<bool>());
break;
case sol::type::number:
if (lua_isinteger(arg.lua_state(), arg.stack_index())) {
store.push_back(lua_tointeger(arg.lua_state(), arg.stack_index()));
} else {
store.push_back(lua_tonumber(arg.lua_state(), arg.stack_index()));
}
break;
case sol::type::string:
store.push_back(arg.as<std::string>());
break;
default:
store.push_back(sol::utility::to_string(sol::stack_object(arg)));
break;
std::vector<LuaFormatArg> formatArgs;
formatArgs.reserve(args.size());
for (const sol::stack_proxy arg : args) {
switch (arg.get_type()) {
case sol::type::boolean:
formatArgs.emplace_back(arg.as<bool>());
break;
case sol::type::number:
if (lua_isinteger(arg.lua_state(), arg.stack_index())) {
formatArgs.emplace_back(lua_tointeger(arg.lua_state(), arg.stack_index()));
} else {
formatArgs.emplace_back(lua_tonumber(arg.lua_state(), arg.stack_index()));
}
break;
case sol::type::string:
formatArgs.emplace_back(arg.as<std::string>());
break;
default:
formatArgs.emplace_back(sol::utility::to_string(sol::stack_object(arg)));
break;
}
formatted = fmt::vformat(fmt, store);
}
#if FMT_EXCEPTIONS
FMT_CATCH(const fmt::format_error &e)
{
// e.what() is undefined if exceptions are disabled, so we wrap it
// with an `FMT_EXCEPTIONS` check.
std::string error = e.what();
#else
FMT_CATCH(const fmt::format_error &)
{
std::string error = "unknown (FMT_EXCEPTIONS disabled)";
#endif
std::string fullError = StrCat("Format error, fmt: ", fmt, " error: ", error);
const std::expected<std::string, std::string> formatted = FormatLuaMessage(fmt, formatArgs);
if (!formatted.has_value()) {
const std::string fullError = StrCat("Format error, fmt: ", fmt, " error: ", formatted.error());
SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, "%s", fullError.c_str());
return;
}
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, static_cast<SDL_LogPriority>(priority), "%s", formatted.c_str());
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, static_cast<SDL_LogPriority>(priority), "%s", formatted->c_str());
}
void LuaLogInfo(std::string_view fmt, sol::variadic_args args)
-1
View File
@@ -2,7 +2,6 @@
#include <string_view>
#include <fmt/format.h>
#include <sol/sol.hpp>
#include "data/file.hpp"
+5 -7
View File
@@ -31,9 +31,6 @@
#include <SDL.h>
#endif
#include <fmt/core.h>
#include <fmt/format.h>
#include "automap.h"
#include "control/control.hpp"
#include "crawl.hpp"
@@ -96,6 +93,7 @@
#include "utils/endian_swap.hpp"
#include "utils/enum_traits.h"
#include "utils/file_name_generator.hpp"
#include "utils/format.hpp"
#include "utils/is_of.hpp"
#include "utils/language.h"
#include "utils/log.hpp"
@@ -4472,9 +4470,9 @@ void M_FallenFear(Point position)
void PrintMonstHistory(int mt)
{
if (*GetOptions().Gameplay.showMonsterType) {
AddInfoBoxString(fmt::format(fmt::runtime(_("Type: {:s} Kills: {:d}")), GetMonsterTypeText(MonstersData[mt]), MonsterKillCounts[mt]));
AddInfoBoxString(FormatRuntime(_("Type: {:s} Kills: {:d}"), GetMonsterTypeText(MonstersData[mt]), MonsterKillCounts[mt]));
} else {
AddInfoBoxString(fmt::format(fmt::runtime(_("Total kills: {:d}")), MonsterKillCounts[mt]));
AddInfoBoxString(FormatRuntime(_("Total kills: {:d}"), MonsterKillCounts[mt]));
}
if (MonsterKillCounts[mt] >= 30) {
@@ -4500,7 +4498,7 @@ void PrintMonstHistory(int mt)
minHP = 4 * minHP + hpBonusHell;
maxHP = 4 * maxHP + hpBonusHell;
}
AddInfoBoxString(fmt::format(fmt::runtime(_("Hit Points: {:d}-{:d}")), minHP, maxHP));
AddInfoBoxString(FormatRuntime(_("Hit Points: {:d}-{:d}"), minHP, maxHP));
}
if (MonsterKillCounts[mt] >= 15) {
const int res = (sgGameInitInfo.nDifficulty != DIFF_HELL) ? MonstersData[mt].resistance : MonstersData[mt].resistanceHell;
@@ -4535,7 +4533,7 @@ void PrintUniqueHistory()
{
const Monster &monster = Monsters[pcursmonst];
if (*GetOptions().Gameplay.showMonsterType) {
AddInfoBoxString(fmt::format(fmt::runtime(_("Type: {:s}")), GetMonsterTypeText(monster.data())));
AddInfoBoxString(FormatRuntime(_("Type: {:s}"), GetMonsterTypeText(monster.data())));
}
const int res = monster.resistance & (RESIST_MAGIC | RESIST_FIRE | RESIST_LIGHTNING | IMMUNE_MAGIC | IMMUNE_FIRE | IMMUNE_LIGHTNING);
+4 -3
View File
@@ -8,6 +8,7 @@
#include <climits>
#include <cmath>
#include <cstdint>
#include <format>
#include <list>
#include <memory>
@@ -18,7 +19,6 @@
#endif
#include <ankerl/unordered_dense.h>
#include <fmt/format.h>
#if !defined(UNPACKED_MPQS) || !defined(UNPACKED_SAVES) || !defined(NONET)
#define USE_PKWARE
@@ -58,6 +58,7 @@
#include "tmsg.h"
#include "towners.h"
#include "utils/endian_swap.hpp"
#include "utils/format.hpp"
#include "utils/is_of.hpp"
#include "utils/language.h"
#include "utils/str_cat.hpp"
@@ -86,7 +87,7 @@ namespace devilution {
void EventFailedPacket(const char *playerName)
{
const std::string message = fmt::format("Player '{}' sent an invalid packet.", playerName);
const std::string message = std::format("Player '{}' sent an invalid packet.", playerName);
EventPlrMsg(message);
}
@@ -2313,7 +2314,7 @@ size_t OnPlayerJoinLevel(const TCmdLocParam2 &message, Player &player)
ResetPlayerGFX(player);
player.plractive = true;
gbActivePlayers++;
EventPlrMsg(fmt::format(fmt::runtime(_("Player '{:s}' (level {:d}) just joined the game")), player._pName, player.getCharacterLevel()));
EventPlrMsg(FormatRuntime(_("Player '{:s}' (level {:d}) just joined the game"), player._pName, player.getCharacterLevel()));
}
if (player.plractive && &player != MyPlayer) {
+7 -6
View File
@@ -8,6 +8,7 @@
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <format>
#include <string_view>
#ifdef USE_SDL3
@@ -19,7 +20,6 @@
#endif
#include <config.h>
#include <fmt/format.h>
#include "DiabloUI/diabloui.h"
#include "diablo.h"
@@ -43,6 +43,7 @@
#include "tmsg.h"
#include "utils/endian_read.hpp"
#include "utils/endian_swap.hpp"
#include "utils/format.hpp"
#include "utils/is_of.hpp"
#include "utils/language.h"
#include "utils/log.hpp"
@@ -302,7 +303,7 @@ void PlayerLeftMsg(Player &player, bool left)
else
LogInfo("Player left the {} game ({}, {}/{} players)", ConnectionNames[provider], reasonDescription, remainingPlayers, MAX_PLRS);
}
EventPlrMsg(fmt::format(fmt::runtime(pszFmt), player._pName));
EventPlrMsg(FormatRuntime(pszFmt, player._pName));
}
player.plractive = false;
player._pName[0] = '\0';
@@ -589,13 +590,13 @@ DVL_API_FOR_TEST std::string DescribeLeaveReason(leaveinfo_t leaveReason)
case leaveinfo_t::LEAVE_DROP:
return "connection timeout";
default:
return fmt::format("code 0x{:08X}", static_cast<uint32_t>(leaveReason));
return std::format("code 0x{:08X}", static_cast<uint32_t>(leaveReason));
}
}
std::string FormatGameSeed(const uint32_t gameSeed[4])
{
return fmt::format("{:08X}{:08X}{:08X}{:08X}",
return std::format("{:08X}{:08X}{:08X}{:08X}",
gameSeed[0], gameSeed[1], gameSeed[2], gameSeed[3]);
}
@@ -894,7 +895,7 @@ bool NetInit(bool bSinglePlayer)
Player &myPlayer = *MyPlayer;
// separator for marking messages from a different game
AddMessageToChatLog(_("New Game"), nullptr, UiFlags::ColorRed);
AddMessageToChatLog(fmt::format(fmt::runtime(_("Player '{:s}' (level {:d}) just joined the game")), myPlayer._pName, myPlayer.getCharacterLevel()));
AddMessageToChatLog(FormatRuntime(_("Player '{:s}' (level {:d}) just joined the game"), myPlayer._pName, myPlayer.getCharacterLevel()));
// Log join message with seed for joining players (creator already logged it in SNetCreateGame)
if (gbIsMultiplayer && !IsLoopback && MyPlayerId != 0) {
@@ -960,7 +961,7 @@ void recv_plrinfo(Player &player, const TCmdPlrInfoHdr &header, bool recv)
} else {
szEvent = _("Player '{:s}' (level {:d}) is already in the game");
}
EventPlrMsg(fmt::format(fmt::runtime(szEvent), player._pName, player.getCharacterLevel()));
EventPlrMsg(FormatRuntime(szEvent, player._pName, player.getCharacterLevel()));
SyncInitPlr(player);
+4 -6
View File
@@ -12,9 +12,6 @@
#include <algorithm>
#include <fmt/core.h>
#include <fmt/format.h>
#include "DiabloUI/ui_flags.hpp"
#include "automap.h"
#include "cursor.h"
@@ -47,6 +44,7 @@
#include "track.h"
#include "utils/algorithm/container.hpp"
#include "utils/endian_swap.hpp"
#include "utils/format.hpp"
#include "utils/is_of.hpp"
#include "utils/language.h"
#include "utils/log.hpp"
@@ -4853,7 +4851,7 @@ StringOrView Object::name() const
return _("Urn");
case OBJ_SHRINEL:
case OBJ_SHRINER:
return fmt::format(fmt::runtime(_(/* TRANSLATORS: {:s} will be a name from the Shrine block above */ "{:s} Shrine")), _(ShrineNames[_oVar1]));
return FormatRuntime(_(/* TRANSLATORS: {:s} will be a name from the Shrine block above */ "{:s} Shrine"), _(ShrineNames[_oVar1]));
case OBJ_SKELBOOK:
return _("Skeleton Tome");
case OBJ_BOOKSTAND:
@@ -4908,12 +4906,12 @@ void GetObjectStr(const Object &object)
const ClassAttributes &classAttributes = GetClassAttributes(MyPlayer->_pClass);
if (HasAnyOf(classAttributes.classFlags, PlayerClassFlag::TrapSense)) {
if (object._oTrapFlag) {
InfoString = fmt::format(fmt::runtime(_(/* TRANSLATORS: {:s} will either be a chest or a door */ "Trapped {:s}")), InfoString.str());
InfoString = FormatRuntime(_(/* TRANSLATORS: {:s} will either be a chest or a door */ "Trapped {:s}"), InfoString.str());
InfoColor = UiFlags::ColorRed;
}
}
if (object.IsDisabled()) {
InfoString = fmt::format(fmt::runtime(_(/* TRANSLATORS: If user enabled diablo.ini setting "Disable Crippling Shrines" is set to 1; also used for Na-Kruls lever */ "{:s} (disabled)")), InfoString.str());
InfoString = FormatRuntime(_(/* TRANSLATORS: If user enabled diablo.ini setting "Disable Crippling Shrines" is set to 1; also used for Na-Kruls lever */ "{:s} (disabled)"), InfoString.str());
InfoColor = UiFlags::ColorRed;
}
}
+16 -9
View File
@@ -27,7 +27,6 @@
#include <SDL_version.h>
#endif
#include <fmt/format.h>
#include <function_ref.hpp>
#include "appfat.h"
@@ -39,6 +38,7 @@
#include "quick_messages.hpp"
#include "utils/algorithm/container.hpp"
#include "utils/file_util.h"
#include "utils/format.hpp"
#include "utils/ini.hpp"
#include "utils/language.h"
#include "utils/log.hpp"
@@ -994,7 +994,14 @@ void OptionEntryLanguageCode::LoadFromIni(std::string_view category)
}
}
LogVerbose("Found user preferred locales: {}", fmt::join(locales, ", "));
if (IsLogLevel(defaultCategory, SDL_LOG_PRIORITY_VERBOSE)) {
std::string joinedLocales;
for (const std::string &locale : locales) {
if (!joinedLocales.empty()) joinedLocales.append(", ");
joinedLocales.append(locale);
}
LogVerbose("Found user preferred locales: {}", joinedLocales);
}
for (const auto &locale : locales) {
LogVerbose("Trying to load translation: {}", locale);
@@ -1180,7 +1187,7 @@ KeymapperOptions::Action::Action(std::string_view key, const char *name, const c
, dynamicIndex(index)
{
if (index != 0) {
dynamicKey = fmt::format(fmt::runtime(std::string_view(key.data(), key.size())), index);
dynamicKey = FormatRuntime(std::string_view(key.data(), key.size()), index);
this->key = dynamicKey;
}
}
@@ -1189,7 +1196,7 @@ std::string_view KeymapperOptions::Action::GetName() const
{
if (dynamicIndex == 0)
return _(name);
dynamicName = fmt::format(fmt::runtime(_(name)), dynamicIndex);
dynamicName = FormatRuntime(_(name), dynamicIndex);
return dynamicName;
}
@@ -1358,7 +1365,7 @@ PadmapperOptions::Action::Action(std::string_view key, const char *name, const c
, dynamicIndex(index)
{
if (index != 0) {
dynamicKey = fmt::format(fmt::runtime(std::string_view(key.data(), key.size())), index);
dynamicKey = FormatRuntime(std::string_view(key.data(), key.size()), index);
this->key = dynamicKey;
}
}
@@ -1367,7 +1374,7 @@ std::string_view PadmapperOptions::Action::GetName() const
{
if (dynamicIndex == 0)
return _(name);
dynamicName = fmt::format(fmt::runtime(_(name)), dynamicIndex);
dynamicName = FormatRuntime(_(name), dynamicIndex);
return dynamicName;
}
@@ -1643,11 +1650,11 @@ std::string BuildModDescription(const ModManifest &manifest)
const bool hasVersion = !manifest.version.empty();
const bool hasAuthor = !manifest.author.empty();
if (hasVersion && hasAuthor)
return fmt::format(fmt::runtime(_("Version {:s} by {:s}")), manifest.version, manifest.author);
return FormatRuntime(_("Version {:s} by {:s}"), manifest.version, manifest.author);
if (hasVersion)
return fmt::format(fmt::runtime(_("Version {:s}")), manifest.version);
return FormatRuntime(_("Version {:s}"), manifest.version);
if (hasAuthor)
return fmt::format(fmt::runtime(_("By {:s}")), manifest.author);
return FormatRuntime(_("By {:s}"), manifest.author);
return {};
}
} // namespace
+2 -3
View File
@@ -6,8 +6,7 @@
#include "pack.h"
#include <cstdint>
#include <fmt/format.h>
#include <format>
#include "engine/random.hpp"
#include "game_mode.hpp"
@@ -46,7 +45,7 @@ namespace {
void EventFailedJoinAttempt(const char *playerName)
{
const std::string message = fmt::format("Player '{}' sent invalid player data during attempt to join the game.", playerName);
const std::string message = std::format("Player '{}' sent invalid player data during attempt to join the game.", playerName);
EventPlrMsg(message);
}
-1
View File
@@ -6,7 +6,6 @@
#include <algorithm>
#include <string>
#include <fmt/format.h>
#include <function_ref.hpp>
#include "control/control.hpp"
+6 -7
View File
@@ -5,8 +5,6 @@
#include <optional>
#include <string>
#include <fmt/format.h>
#include "control/control.hpp"
#include "engine/backbuffer_state.hpp"
#include "engine/clx_sprite.hpp"
@@ -21,6 +19,7 @@
#include "panels/ui_panels.hpp"
#include "player.h"
#include "tables/spelldat.h"
#include "utils/format.hpp"
#include "utils/language.h"
#include "utils/status_macros.hpp"
@@ -112,9 +111,9 @@ StringOrView GetSpellPowerText(SpellID spell, int spellLevel)
return StringOrView {};
}
if (spell == SpellID::Healing || spell == SpellID::HealOther) {
return fmt::format(fmt::runtime(_(/* TRANSLATORS: UI constraints, keep short please.*/ "Heals: {:d} - {:d}")), min, max);
return FormatRuntime(_(/* TRANSLATORS: UI constraints, keep short please.*/ "Heals: {:d} - {:d}"), min, max);
}
return fmt::format(fmt::runtime(_(/* TRANSLATORS: UI constraints, keep short please.*/ "Damage: {:d} - {:d}")), min, max);
return FormatRuntime(_(/* TRANSLATORS: UI constraints, keep short please.*/ "Damage: {:d} - {:d}"), min, max);
}
} // namespace
@@ -173,16 +172,16 @@ void DrawSpellBook(const Surface &out)
break;
case SpellType::Charges: {
const int charges = player.InvBody[INVLOC_HAND_LEFT]._iCharges;
PrintSBookStr(out, line1, fmt::format(fmt::runtime(ngettext("Staff ({:d} charge)", "Staff ({:d} charges)", charges)), charges));
PrintSBookStr(out, line1, FormatRuntime(ngettext("Staff ({:d} charge)", "Staff ({:d} charges)", charges), charges));
} break;
default: {
const int mana = GetManaAmount(player, sn) >> 6;
const int lvl = player.GetSpellLevel(sn);
PrintSBookStr(out, line0, fmt::format(fmt::runtime(pgettext(/* TRANSLATORS: UI constraints, keep short please.*/ "spellbook", "Level {:d}")), lvl), UiFlags::AlignRight);
PrintSBookStr(out, line0, FormatRuntime(pgettext(/* TRANSLATORS: UI constraints, keep short please.*/ "spellbook", "Level {:d}"), lvl), UiFlags::AlignRight);
if (const StringOrView text = GetSpellPowerText(sn, lvl); !text.empty()) {
PrintSBookStr(out, line1, text, UiFlags::AlignRight);
}
PrintSBookStr(out, line1, fmt::format(fmt::runtime(pgettext(/* TRANSLATORS: UI constraints, keep short please.*/ "spellbook", "Mana: {:d}")), mana));
PrintSBookStr(out, line1, FormatRuntime(pgettext(/* TRANSLATORS: UI constraints, keep short please.*/ "spellbook", "Mana: {:d}"), mana));
} break;
}
}
+9 -10
View File
@@ -2,8 +2,6 @@
#include <cstdint>
#include <fmt/format.h>
#include "control/control.hpp"
#include "controls/control_mode.hpp"
#include "controls/plrctrls.h"
@@ -17,6 +15,7 @@
#include "player.h"
#include "spells.h"
#include "utils/algorithm/container.hpp"
#include "utils/format.hpp"
#include "utils/language.h"
#include "utils/str_cat.hpp"
#include "utils/utf8.hpp"
@@ -150,48 +149,48 @@ void DrawSpellList(const Surface &out)
case SpellType::Skill:
spellColor = PAL16_YELLOW - 46;
PrintSBookSpellType(out, spellListItem.location, _("Skill"), spellColor);
InfoString = fmt::format(fmt::runtime(_("{:s} Skill")), pgettext("spell", spellDataItem.sNameText));
InfoString = FormatRuntime(_("{:s} Skill"), pgettext("spell", spellDataItem.sNameText));
break;
case SpellType::Spell:
if (!myPlayer.isOnLevel(0)) {
spellColor = PAL16_BLUE + 5;
}
PrintSBookSpellType(out, spellListItem.location, _("Spell"), spellColor);
InfoString = fmt::format(fmt::runtime(_("{:s} Spell")), pgettext("spell", spellDataItem.sNameText));
InfoString = FormatRuntime(_("{:s} Spell"), pgettext("spell", spellDataItem.sNameText));
if (spellId == SpellID::HolyBolt) {
AddInfoBoxString(_("Damages undead only"));
}
if (spellLevel == 0)
AddInfoBoxString(_("Spell Level 0 - Unusable"));
else
AddInfoBoxString(fmt::format(fmt::runtime(_("Spell Level {:d}")), spellLevel));
AddInfoBoxString(FormatRuntime(_("Spell Level {:d}"), spellLevel));
break;
case SpellType::Scroll: {
if (!myPlayer.isOnLevel(0)) {
spellColor = PAL16_RED - 59;
}
PrintSBookSpellType(out, spellListItem.location, _("Scroll"), spellColor);
InfoString = fmt::format(fmt::runtime(_("Scroll of {:s}")), pgettext("spell", spellDataItem.sNameText));
InfoString = FormatRuntime(_("Scroll of {:s}"), pgettext("spell", spellDataItem.sNameText));
const int scrollCount = c_count_if(InventoryAndBeltPlayerItemsRange { myPlayer }, [spellId](const Item &item) {
return item.isScrollOf(spellId);
});
AddInfoBoxString(fmt::format(fmt::runtime(ngettext("{:d} Scroll", "{:d} Scrolls", scrollCount)), scrollCount));
AddInfoBoxString(FormatRuntime(ngettext("{:d} Scroll", "{:d} Scrolls", scrollCount), scrollCount));
} break;
case SpellType::Charges: {
if (!myPlayer.isOnLevel(0)) {
spellColor = PAL16_ORANGE + 5;
}
PrintSBookSpellType(out, spellListItem.location, _("Staff"), spellColor);
InfoString = fmt::format(fmt::runtime(_("Staff of {:s}")), pgettext("spell", spellDataItem.sNameText));
InfoString = FormatRuntime(_("Staff of {:s}"), pgettext("spell", spellDataItem.sNameText));
int charges = myPlayer.InvBody[INVLOC_HAND_LEFT]._iCharges;
AddInfoBoxString(fmt::format(fmt::runtime(ngettext("{:d} Charge", "{:d} Charges", charges)), charges));
AddInfoBoxString(FormatRuntime(ngettext("{:d} Charge", "{:d} Charges", charges), charges));
} break;
case SpellType::Invalid:
break;
}
std::optional<std::string_view> fullHotkeyName = GetHotkeyName(spellId, spellListItem.type);
if (fullHotkeyName) {
AddInfoBoxString(fmt::format(fmt::runtime(_("Spell Hotkey {:s}")), *fullHotkeyName));
AddInfoBoxString(FormatRuntime(_("Spell Hotkey {:s}"), *fullHotkeyName));
}
}
}
+18
View File
@@ -0,0 +1,18 @@
/*
* The m68k-amigaos hard-float libgcc multilib omits the software
* double-precision comparison routine `__cmpdf2` (doubles are compared in
* hardware), but its software extended-precision comparison routines
* (xfpgnulib `__cmpxf2`, `__eqxf2`, ...) still call it.
*
* libstdc++'s <format> machinery references the extended-precision routines
* through its `long double` code paths, so linking fails with an undefined
* `__cmpdf2` even though it is never actually called.
*/
int __cmpdf2(double a, double b);
int __cmpdf2(double a, double b)
{
if (a < b) return -1;
if (a > b) return 1;
return 0;
}
-1
View File
@@ -26,7 +26,6 @@ endif()
target_link_dependencies(libdevilutionx_ctr
PUBLIC
DevilutionX::SDL
fmt::fmt
3ds::citro3d
3ds::ctrulib
PRIVATE
-6
View File
@@ -3,12 +3,6 @@
#include <cstdint>
#include <malloc.h>
// This header must be included before any 3DS code
// because 3DS SDK defines a macro with the same name
// as an fmt template parameter in some versions of fmt.
// See https://github.com/fmtlib/fmt/issues/3632
#include <fmt/core.h>
#include <3ds.h>
#include "utils/log.hpp"
+2 -4
View File
@@ -14,9 +14,6 @@
#include <SDL.h>
#endif
#include <fmt/core.h>
#include <fmt/format.h>
#include "control/control.hpp"
#include "controls/control_mode.hpp"
#include "controls/plrctrls.h"
@@ -55,6 +52,7 @@
#include "spells.h"
#include "stores.h"
#include "towners.h"
#include "utils/format.hpp"
#include "utils/is_of.hpp"
#include "utils/language.h"
#include "utils/log.hpp"
@@ -2749,7 +2747,7 @@ StartPlayerKill(Player &player, DeathReason deathReason)
if (dropEar) {
Item ear;
InitializeItem(ear, IDI_EAR);
CopyUtf8(ear._iName, fmt::format(fmt::runtime("Ear of {:s}"), player._pName), sizeof(ear._iName));
CopyUtf8(ear._iName, FormatRuntime("Ear of {:s}", player._pName), sizeof(ear._iName));
CopyUtf8(ear._iIName, player._pName, ItemNameLength);
switch (player._pClass) {
case HeroClass::Sorcerer:
+2 -3
View File
@@ -15,8 +15,6 @@
#include <SDL.h>
#endif
#include <fmt/format.h>
#include "control/control.hpp"
#include "engine/render/primitive_render.hpp"
#include "engine/render/text_render.hpp"
@@ -24,6 +22,7 @@
#include "qol/chatlog.h"
#include "qol/stash.h"
#include "utils/algorithm/container.hpp"
#include "utils/format.hpp"
#include "utils/language.h"
#include "utils/utf8.hpp"
@@ -82,7 +81,7 @@ void SendPlrMsg(Player &player, std::string_view text)
{
PlayerMessage &message = GetNextMessage();
const std::string from = fmt::format(fmt::runtime(_("{:s} (lvl {:d}): ")), player._pName, player.getCharacterLevel());
const std::string from = FormatRuntime(_("{:s} (lvl {:d}): "), player._pName, player.getCharacterLevel());
message.style = UiFlags::ColorWhite;
message.time = SDL_GetTicks();
+3 -4
View File
@@ -9,8 +9,6 @@
#include <string_view>
#include <vector>
#include <fmt/format.h>
#include "DiabloUI/ui_flags.hpp"
#include "automap.h"
#include "chatlog.h"
@@ -23,6 +21,7 @@
#include "inv.h"
#include "minitext.h"
#include "stores.h"
#include "utils/format.hpp"
#include "utils/language.h"
#include "utils/str_cat.hpp"
@@ -127,7 +126,7 @@ void AddMessageToChatLog(std::string_view message, Player *player, UiFlags flags
if (player == nullptr) {
ChatLogLines.emplace_back(MultiColoredText { "{0} {1}", { { timestamp, UiFlags::ColorRed }, { std::string(message), flags } } });
} else {
std::string playerInfo = fmt::format(fmt::runtime(_("{:s} (lvl {:d}): ")), player->_pName, player->getCharacterLevel());
std::string playerInfo = FormatRuntime(_("{:s} (lvl {:d}): "), player->_pName, player->getCharacterLevel());
UiFlags nameColor = player == MyPlayer ? UiFlags::ColorWhitegold : UiFlags::ColorBlue;
const std::string prefix = timestamp + " - " + playerInfo;
const std::string text = WordWrapString(prefix + std::string(message), ContentTextWidth);
@@ -167,7 +166,7 @@ void DrawChatLog(const Surface &out)
const int sx = uiPosition.x + PaddingLeft;
const int sy = uiPosition.y;
DrawString(out, fmt::format(fmt::runtime(_("Chat History (Messages: {:d})")), MessageCounter),
DrawString(out, FormatRuntime(_("Chat History (Messages: {:d})"), MessageCounter),
{ { sx, sy + PaddingTop + blankLineHeight }, { ContentTextWidth, lineHeight } },
{ .flags = (UnreadFlag ? UiFlags::ColorRed : UiFlags::ColorWhitegold) | UiFlags::AlignCenter });
-1
View File
@@ -3,7 +3,6 @@
#include <cstdint>
#include <ctime>
#include <deque>
#include <fmt/format.h>
#include <string>
#ifdef USE_SDL3
+2 -3
View File
@@ -7,8 +7,6 @@
#include <string_view>
#include <vector>
#include <fmt/format.h>
#include "control/control.hpp"
#include "cursor.h"
#include "engine/point.hpp"
@@ -20,6 +18,7 @@
#include "qol/stash.h"
#include "stores.h"
#include "utils/algorithm/container.hpp"
#include "utils/format.hpp"
#include "utils/format_int.hpp"
#include "utils/language.h"
@@ -110,7 +109,7 @@ void AddItemToLabelQueue(int id, Point position)
StringOrView textOnGround;
if (item._itype == ItemType::Gold) {
textOnGround = fmt::format(fmt::runtime(_("{:s} gold")), FormatInteger(item._ivalue));
textOnGround = FormatRuntime(_("{:s} gold"), FormatInteger(item._ivalue));
} else {
textOnGround = item.getName();
}
-2
View File
@@ -7,8 +7,6 @@
#include <cstdint>
#include <fmt/format.h>
#include "control/control.hpp"
#include "cursor.h"
#include "engine/clx_sprite.hpp"
-2
View File
@@ -10,8 +10,6 @@
#include <SDL.h>
#endif
#include <fmt/format.h>
#include "DiabloUI/text_input.hpp"
#include "control/control.hpp"
#include "controls/plrctrls.h"
+6 -8
View File
@@ -8,9 +8,6 @@
#include <array>
#include <cstdint>
#include <fmt/core.h>
#include <fmt/format.h>
#include "control/control.hpp"
#include "engine/clx_sprite.hpp"
#include "engine/load_clx.hpp"
@@ -20,6 +17,7 @@
#include "game_mode.hpp"
#include "options.h"
#include "tables/playerdat.hpp"
#include "utils/format.hpp"
#include "utils/format_int.hpp"
#include "utils/language.h"
@@ -137,13 +135,13 @@ bool CheckXPBarInfo()
const uint8_t charLevel = player.getCharacterLevel();
AddInfoBoxString(fmt::format(fmt::runtime(_("Level {:d}")), charLevel));
AddInfoBoxString(FormatRuntime(_("Level {:d}"), charLevel));
if (player.isMaxCharacterLevel()) {
// Show a maximum level indicator for max level players.
InfoColor = UiFlags::ColorWhitegold;
AddInfoBoxString(fmt::format(fmt::runtime(_("Experience: {:s}")), FormatInteger(player._pExperience)));
AddInfoBoxString(FormatRuntime(_("Experience: {:s}"), FormatInteger(player._pExperience)));
AddInfoBoxString(_("Maximum Level"));
return true;
@@ -151,10 +149,10 @@ bool CheckXPBarInfo()
InfoColor = UiFlags::ColorWhite;
AddInfoBoxString(fmt::format(fmt::runtime(_("Experience: {:s}")), FormatInteger(player._pExperience)));
AddInfoBoxString(FormatRuntime(_("Experience: {:s}"), FormatInteger(player._pExperience)));
const uint32_t nextExperienceThreshold = player.getNextExperienceThreshold();
AddInfoBoxString(fmt::format(fmt::runtime(_("Next Level: {:s}")), FormatInteger(nextExperienceThreshold)));
AddInfoBoxString(fmt::format(fmt::runtime(_("{:s} to Level {:d}")), FormatInteger(nextExperienceThreshold - player._pExperience), charLevel + 1));
AddInfoBoxString(FormatRuntime(_("Next Level: {:s}"), FormatInteger(nextExperienceThreshold)));
AddInfoBoxString(FormatRuntime(_("{:s} to Level {:d}"), FormatInteger(nextExperienceThreshold - player._pExperience), charLevel + 1));
return true;
}
+2 -3
View File
@@ -7,8 +7,6 @@
#include <cstdint>
#include <fmt/format.h>
#include "DiabloUI/ui_flags.hpp"
#include "control/control.hpp"
#include "cursor.h"
@@ -32,6 +30,7 @@
#include "tables/townerdat.hpp"
#include "towners.h"
#include "utils/endian_swap.hpp"
#include "utils/format.hpp"
#include "utils/is_of.hpp"
#include "utils/language.h"
#include "utils/utf8.hpp"
@@ -354,7 +353,7 @@ bool ForceQuests()
const int ql = quest._qslvl - 1;
if (EntranceBoundaryContains(quest.position, cursPosition)) {
InfoString = fmt::format(fmt::runtime(_(/* TRANSLATORS: Used for Quest Portals. {:s} is a Map Name */ "To {:s}")), _(QuestTriggerNames[ql]));
InfoString = FormatRuntime(_(/* TRANSLATORS: Used for Quest Portals. {:s} is a Map Name */ "To {:s}"), _(QuestTriggerNames[ql]));
cursPosition = quest.position;
return true;
}
+11 -12
View File
@@ -13,8 +13,6 @@
#include <utility>
#include <vector>
#include <fmt/format.h>
#include "controls/control_mode.hpp"
#include "controls/plrctrls.h"
#include "cursor.h"
@@ -34,6 +32,7 @@
#include "qol/visual_store.h"
#include "tables/townerdat.hpp"
#include "towners.h"
#include "utils/format.hpp"
#include "utils/format_int.hpp"
#include "utils/language.h"
#include "utils/log.hpp"
@@ -370,7 +369,7 @@ void PrintStoreItem(const Item &item, int l, UiFlags flags, bool cursIndent = fa
if (item._iMiscId == IMISC_STAFF && item._iMaxCharges != 0) {
if (!productLine.empty())
productLine.append(_(", "));
productLine.append(fmt::format(fmt::runtime(_("Charges: {:d}/{:d}")), item._iCharges, item._iMaxCharges));
productLine.append(FormatRuntime(_("Charges: {:d}/{:d}"), item._iCharges, item._iMaxCharges));
}
if (!productLine.empty()) {
AddSText(40, l, productLine, flags, false, -1, cursIndent);
@@ -380,11 +379,11 @@ void PrintStoreItem(const Item &item, int l, UiFlags flags, bool cursIndent = fa
if (item._itype != ItemType::Misc) {
if (item._iClass == ICLASS_WEAPON)
productLine = fmt::format(fmt::runtime(_("Damage: {:d}-{:d} ")), item._iMinDam, item._iMaxDam);
productLine = FormatRuntime(_("Damage: {:d}-{:d} "), item._iMinDam, item._iMaxDam);
else if (item._iClass == ICLASS_ARMOR)
productLine = fmt::format(fmt::runtime(_("Armor: {:d} ")), item._iAC);
productLine = FormatRuntime(_("Armor: {:d} "), item._iAC);
if (item._iMaxDur != DUR_INDESTRUCTIBLE && item._iMaxDur != 0)
productLine += fmt::format(fmt::runtime(_("Dur: {:d}/{:d}")), item._iDurability, item._iMaxDur);
productLine += FormatRuntime(_("Dur: {:d}/{:d}"), item._iDurability, item._iMaxDur);
else
productLine.append(_("Indestructible"));
}
@@ -398,11 +397,11 @@ void PrintStoreItem(const Item &item, int l, UiFlags flags, bool cursIndent = fa
productLine.append(_(", "));
productLine.append(_("Required:"));
if (str != 0)
productLine.append(fmt::format(fmt::runtime(_(" {:d} Str")), str));
productLine.append(FormatRuntime(_(" {:d} Str"), str));
if (mag != 0)
productLine.append(fmt::format(fmt::runtime(_(" {:d} Mag")), mag));
productLine.append(FormatRuntime(_(" {:d} Mag"), mag));
if (dex != 0)
productLine.append(fmt::format(fmt::runtime(_(" {:d} Dex")), dex));
productLine.append(FormatRuntime(_(" {:d} Dex"), dex));
}
AddSText(40, l++, productLine, flags, false, -1, cursIndent);
}
@@ -1207,10 +1206,10 @@ void StartTalk()
IsTextFullSize = false;
HasScrollbar = false;
AddSText(0, 2, fmt::format(fmt::runtime(_("Talk to {:s}")), _(TownerNames[TownerId])), UiFlags::ColorWhitegold | UiFlags::AlignCenter, false);
AddSText(0, 2, FormatRuntime(_("Talk to {:s}"), _(TownerNames[TownerId])), UiFlags::ColorWhitegold | UiFlags::AlignCenter, false);
AddSLine(5);
if (gbIsSpawn) {
AddSText(0, 10, fmt::format(fmt::runtime(_("Talking to {:s}")), _(TownerNames[TownerId])), UiFlags::ColorWhite | UiFlags::AlignCenter, false);
AddSText(0, 10, FormatRuntime(_("Talking to {:s}"), _(TownerNames[TownerId])), UiFlags::ColorWhite | UiFlags::AlignCenter, false);
AddSText(0, 12, _("is not available"), UiFlags::ColorWhite | UiFlags::AlignCenter, false);
AddSText(0, 14, _("in the shareware"), UiFlags::ColorWhite | UiFlags::AlignCenter, false);
AddSText(0, 16, _("version"), UiFlags::ColorWhite | UiFlags::AlignCenter, false);
@@ -2471,7 +2470,7 @@ void DrawSText(const Surface &out)
}
if (RenderGold) {
PrintSString(out, 28, 1, fmt::format(fmt::runtime(_("Your gold: {:s}")), FormatInteger(TotalPlayerGold())).c_str(), UiFlags::ColorWhitegold | UiFlags::AlignRight);
PrintSString(out, 28, 1, FormatRuntime(_("Your gold: {:s}"), FormatInteger(TotalPlayerGold())).c_str(), UiFlags::ColorWhitegold | UiFlags::AlignRight);
}
if (HasScrollbar)
+4 -5
View File
@@ -6,11 +6,10 @@
#include "tables/itemdat.h"
#include <format>
#include <string_view>
#include <vector>
#include <fmt/format.h>
#include "data/file.hpp"
#include "data/iterators.hpp"
#include "data/record_reader.hpp"
@@ -367,7 +366,7 @@ std::expected<unique_base_item, std::string> ParseOrAddUniqueBaseItem(std::strin
const size_t newUniqueBaseItemIndex = static_cast<size_t>(NUM_DEFAULT_UITYPES) + AdditionalUniqueBaseItemStringsToIndices.size();
if (newUniqueBaseItemIndex >= static_cast<size_t>(NUM_MAX_UITYPES)) {
return std::unexpected(fmt::format("Could not define new unique base item \"{}\", since the maximum number of {} has already been reached.", value, static_cast<size_t>(NUM_MAX_UITYPES)));
return std::unexpected(std::format("Could not define new unique base item \"{}\", since the maximum number of {} has already been reached.", value, static_cast<size_t>(NUM_MAX_UITYPES)));
}
const auto newUniqueBaseItem = static_cast<unique_base_item>(newUniqueBaseItemIndex);
@@ -599,7 +598,7 @@ void LoadItemDatFromFile(DataFile &dataFile, std::string_view filename, int32_t
item.iMappingId = currentMappingId;
const auto [it, inserted] = ItemMappingIdsToIndices.emplace(item.iMappingId, static_cast<int16_t>(AllItemsList.size()) - 1);
if (!inserted) {
DisplayFatalErrorAndExit("Adding Item Failed", fmt::format("An item already exists for mapping ID {}.", item.iMappingId));
DisplayFatalErrorAndExit("Adding Item Failed", std::format("An item already exists for mapping ID {}.", item.iMappingId));
}
++currentMappingId;
@@ -657,7 +656,7 @@ void LoadUniqueItemDatFromFile(DataFile &dataFile, std::string_view filename, in
item.mappingId = currentMappingId;
const auto [it, inserted] = UniqueItemMappingIdsToIndices.emplace(item.mappingId, static_cast<int32_t>(UniqueItems.size()) - 1);
if (!inserted) {
DisplayFatalErrorAndExit("Adding Unique Item Failed", fmt::format("A unique item already exists for mapping ID {}.", item.mappingId));
DisplayFatalErrorAndExit("Adding Unique Item Failed", std::format("A unique item already exists for mapping ID {}.", item.mappingId));
}
++currentMappingId;
+3 -4
View File
@@ -15,8 +15,6 @@
#include <vector>
#include <ankerl/unordered_dense.h>
#include <fmt/core.h>
#include <fmt/format.h>
#include <magic_enum/magic_enum.hpp>
#include "appfat.h"
@@ -28,6 +26,7 @@
#include "lua/lua_event.hpp"
#include "monster.h"
#include "tables/textdat.h"
#include "utils/format.hpp"
#include "utils/language.h"
namespace devilution {
@@ -329,7 +328,7 @@ void LoadMonstDatFromFile(DataFile &dataFile, const std::string_view filename, b
for (DataFileRecord record : dataFile) {
if (MonstersData.size() >= static_cast<size_t>(NUM_MAX_MTYPES)) {
DisplayFatalErrorAndExit(_("Loading Monster Data Failed"), fmt::format(fmt::runtime(_("Could not add a monster, since the maximum monster type number of {} has already been reached.")), static_cast<size_t>(NUM_MAX_MTYPES)));
DisplayFatalErrorAndExit(_("Loading Monster Data Failed"), FormatRuntime(_("Could not add a monster, since the maximum monster type number of {} has already been reached."), static_cast<size_t>(NUM_MAX_MTYPES)));
}
RecordReader reader { record, filename };
@@ -342,7 +341,7 @@ void LoadMonstDatFromFile(DataFile &dataFile, const std::string_view filename, b
const size_t monsterIndex = MonstersData.size();
const auto [it, inserted] = AdditionalMonsterIdStringsToIndices.emplace(monsterId, static_cast<int16_t>(monsterIndex));
if (!inserted) {
DisplayFatalErrorAndExit(_("Loading Monster Data Failed"), fmt::format(fmt::runtime(_("A monster type already exists for ID \"{}\".")), monsterId));
DisplayFatalErrorAndExit(_("Loading Monster Data Failed"), FormatRuntime(_("A monster type already exists for ID \"{}\"."), monsterId));
}
}
+2 -2
View File
@@ -14,7 +14,6 @@
#include <expected>
#include <vector>
#include <fmt/format.h>
#include <magic_enum/magic_enum_utility.hpp>
#include "data/file.hpp"
@@ -23,6 +22,7 @@
#include "items.h"
#include "player.h"
#include "tables/textdat.h"
#include "utils/format.hpp"
#include "utils/language.h"
#include "utils/static_vector.hpp"
#include "utils/str_cat.hpp"
@@ -317,7 +317,7 @@ void LoadClassDatFromFile(DataFile &dataFile, const std::string_view filename)
for (DataFileRecord record : dataFile) {
if (PlayersData.size() >= static_cast<size_t>(HeroClass::NUM_MAX_CLASSES)) {
DisplayFatalErrorAndExit(_("Loading Class Data Failed"), fmt::format(fmt::runtime(_("Could not add a class, since the maximum class number of {} has already been reached.")), static_cast<size_t>(HeroClass::NUM_MAX_CLASSES)));
DisplayFatalErrorAndExit(_("Loading Class Data Failed"), FormatRuntime(_("Could not add a class, since the maximum class number of {} has already been reached."), static_cast<size_t>(HeroClass::NUM_MAX_CLASSES)));
}
RecordReader reader { record, filename };
+2 -3
View File
@@ -6,13 +6,12 @@
#include "tables/textdat.h"
#include <ankerl/unordered_dense.h>
#include <fmt/core.h>
#include <fmt/format.h>
#include <magic_enum/magic_enum.hpp>
#include "data/file.hpp"
#include "data/record_reader.hpp"
#include "effects.h"
#include "utils/format.hpp"
#include "utils/language.h"
namespace devilution {
@@ -70,7 +69,7 @@ void LoadTextDatFromFile(DataFile &dataFile, std::string_view filename, bool gro
const size_t textEntryIndex = Speeches.size();
const auto [it, inserted] = AdditionalTextIdStringsToIndices.emplace(txtstrid, static_cast<int16_t>(textEntryIndex));
if (!inserted) {
DisplayFatalErrorAndExit(_("Loading Text Data Failed"), fmt::format(fmt::runtime(_("A text data entry already exists for ID \"{}\".")), txtstrid));
DisplayFatalErrorAndExit(_("Loading Text Data Failed"), FormatRuntime(_("A text data entry already exists for ID \"{}\"."), txtstrid));
}
}
+22
View File
@@ -0,0 +1,22 @@
#pragma once
#include <format>
#include <string>
#include <string_view>
namespace devilution {
/**
* @brief Formats using a format string that is only known at runtime, such as a translation.
*
* Unlike `std::format`, the format string is not checked at compile time.
* An invalid format string results in `std::format_error` being thrown
* (or program termination if exceptions are disabled).
*/
template <typename... Args>
[[nodiscard]] std::string FormatRuntime(std::string_view fmt, Args &&...args)
{
return std::vformat(fmt, std::make_format_args(args...));
}
} // namespace devilution
+8 -13
View File
@@ -7,6 +7,7 @@
#include <cstdlib>
#include <cstring>
#include <expected>
#include <format>
#include <span>
#include <string>
#include <string_view>
@@ -16,8 +17,6 @@
#include <vector>
#include <ankerl/unordered_dense.h>
#include <fmt/core.h>
#include <fmt/format.h>
#include "utils/algorithm/container.hpp"
#include "utils/str_cat.hpp"
@@ -160,10 +159,10 @@ std::expected<Ini, std::string> Ini::parse(std::string_view buffer)
++keyEnd;
}
if (keyEnd == lineEnd) {
return std::unexpected(fmt::format("line {}: unclosed section name {}", lineNum, std::string_view(keyBegin, keyEnd - keyBegin)));
return std::unexpected(std::format("line {}: unclosed section name {}", lineNum, std::string_view(keyBegin, keyEnd - keyBegin)));
}
if (const char *after = SkipTrailingWhitespace(keyEnd + 1, lineEnd); after != lineEnd) {
return std::unexpected(fmt::format("line {}: content after section [{}]: {}", lineNum, std::string_view(keyBegin, keyEnd - keyBegin), std::string_view(after, lineEnd - after)));
return std::unexpected(std::format("line {}: content after section [{}]: {}", lineNum, std::string_view(keyBegin, keyEnd - keyBegin), std::string_view(after, lineEnd - after)));
}
const std::string_view sectionName = std::string_view(keyBegin, keyEnd - keyBegin);
auto it = fileData.sections.find(sectionName);
@@ -180,10 +179,10 @@ std::expected<Ini, std::string> Ini::parse(std::string_view buffer)
continue;
}
if (sectionEntries == nullptr) return std::unexpected(fmt::format("line {}: key not in any section", lineNum));
if (sectionEntries == nullptr) return std::unexpected(std::format("line {}: key not in any section", lineNum));
const char *eqPos = static_cast<const char *>(memchr(keyBegin, '=', lineEnd - keyBegin));
if (eqPos == nullptr) {
return std::unexpected(fmt::format("line {}: key {} has no value", lineNum, std::string_view(keyBegin, lineEnd - keyBegin)));
return std::unexpected(std::format("line {}: key {} has no value", lineNum, std::string_view(keyBegin, lineEnd - keyBegin)));
}
const char *keyEnd = SkipTrailingWhitespace(keyBegin, eqPos);
const std::string_view key = std::string_view(keyBegin, keyEnd - keyBegin);
@@ -230,7 +229,7 @@ int Ini::getInt(std::string_view section, std::string_view key, int defaultValue
int value;
const std::from_chars_result result = std::from_chars(str.data(), str.data() + str.size(), value);
if (result.ec != std::errc()) {
app_fatal(fmt::format("ini: Failed to parse {}.{}={} as int", section, key, str));
app_fatal(std::format("ini: Failed to parse {}.{}={} as int", section, key, str));
return defaultValue;
}
return value;
@@ -243,7 +242,7 @@ bool Ini::getBool(std::string_view section, std::string_view key, bool defaultVa
const std::string_view str = xs.back().value;
if (str == "0") return false;
if (str == "1") return true;
app_fatal(fmt::format("ini: Failed to parse {}.{}={} as bool", section, key, str));
app_fatal(std::format("ini: Failed to parse {}.{}={} as bool", section, key, str));
}
float Ini::getFloat(std::string_view section, std::string_view key, float defaultValue) const
@@ -256,7 +255,7 @@ float Ini::getFloat(std::string_view section, std::string_view key, float defaul
float value;
const std::from_chars_result result = std::from_chars(str.data(), str.data() + str.size(), value);
if (result.ec != std::errc()) {
app_fatal(fmt::format("ini: Failed to parse {}.{}={} as float", section, key, str));
app_fatal(std::format("ini: Failed to parse {}.{}={} as float", section, key, str));
return defaultValue;
}
return value;
@@ -375,7 +374,6 @@ void Ini::set(std::string_view section, std::string_view key, bool value)
void Ini::set(std::string_view section, std::string_view key, float value)
{
#if __cpp_lib_to_chars >= 201611L
constexpr size_t BufSize = 64;
char buf[BufSize] {};
const std::to_chars_result result = std::to_chars(buf, buf + BufSize, value);
@@ -383,9 +381,6 @@ void Ini::set(std::string_view section, std::string_view key, float value)
app_fatal("float->string failed"); // should never happen
}
set(section, key, std::string_view(buf, result.ptr - buf));
#else
set(section, key, fmt::format("{}", value));
#endif
}
namespace {
+10
View File
@@ -3,6 +3,16 @@
#include <string>
#include <string_view>
// libstdc++'s <locale> (which <format> includes in GCC 13) includes
// <libintl.h>, which declares `ngettext`. Include it before defining the
// `ngettext` macro below, so that the declaration is not rewritten into a
// conflicting `LanguagePluralTranslate` overload that is never defined.
#if __has_include(<libintl.h>)
#include <libintl.h>
// GNU libintl.h may define `ngettext` as a macro itself.
#undef ngettext
#endif
#define _(x) LanguageTranslate(x)
#define ngettext(x, y, z) LanguagePluralTranslate(x, y, z)
#define pgettext(context, x) LanguageParticularTranslate(context, x)
+12 -19
View File
@@ -8,10 +8,10 @@
#include <SDL.h>
#endif
#include <fmt/core.h>
#include <fmt/format.h>
#include <fmt/ranges.h>
#include <format>
#include <string>
#include "utils/attributes.h"
#include "utils/str_cat.hpp"
#ifdef USE_SDL1
@@ -51,25 +51,18 @@ namespace detail {
template <typename... Args>
std::string format(std::string_view fmt, Args &&...args)
{
FMT_TRY
{
return fmt::format(fmt::runtime(fmt), std::forward<Args>(args)...);
#if DVL_EXCEPTIONS
try {
return std::vformat(fmt, std::make_format_args(args...));
} catch (const std::format_error &e) {
const std::string fullError = StrCat("Format error, fmt: ", fmt, " error: ", e.what());
SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, "%s", fullError.c_str());
app_fatal(fullError);
}
#if FMT_EXCEPTIONS
FMT_CATCH(const fmt::format_error &e)
{
// e.what() is undefined if exceptions are disabled, so we wrap it
// with an `FMT_EXCEPTIONS` check.
std::string error = e.what();
#else
FMT_CATCH(const fmt::format_error &)
{
std::string error = "unknown (FMT_EXCEPTIONS disabled)";
// `std::vformat` terminates the program on error when exceptions are disabled.
return std::vformat(fmt, std::make_format_args(args...));
#endif
std::string fullError = StrCat("Format error, fmt: ", fmt, " error: ", error);
SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, "%s", error.c_str());
app_fatal(error);
}
}
} // namespace detail
Loaded 100 of 109 files, more files were not shown because too many files have changed in this diff. Show more