Rather than using the Windows-like `MAX_PATH`, what we really want is 2
things:
1. Maximum path of a file in an MPQ. This is now `MaxMpqPathSize`.
2. Max size for the known monster paths. This is now 64 for sounds and
TRNs, which is more than enough (picked arbitrarily).
1. Store all key data and all values data as 2 char arrays.
2. Change map keys to char pointers.
3. Change map values to offsets into the values array.
Example savings for Russian: 460 KiB -> 374.2 KiB (-85.8 KiB)
* Map: 68.5 KiB (with `string_view` keys it would be 101.5 KiB)
* Keys array: 108.7 KiB
* Values array: 197.0 KiB
1. Do not modify the map after loading. Instead, return string views
(guaranteed to be null-terminated) from look up functions and return
the key directly if not found.
2. Use an `unorded_map` instead of `map` where available (C++20).
Saves a bit of RAM (~50 KiB) and improves lookup performance.
We ensure that selectable lines are placed at the same vertical
coordinates but space out unselectable text lines at the cost
of reduced heigh of empty space between the store items.
We also have to move the back button in scrollable lists to the
lower right.
This can definitely be improved further but at least it solves
the problem for now.
Refs #3162
libmpq is a much simpler alternative to StormLib for reading MPQ archives.
We use our own fork of libmpq: https://github.com/diasurgical/libmpq
Impact:
* DevilutionX is now a lot more portable. Unlike StormLib, libmpq only
needs platform-specific code for Windows.
* Locks around file access **removed** (instead we duplicate the file descriptor for streamed audio only).
* RAM usage is **300 KiB** lower than StormLib.
* Stripped release linux_x86_64 binary is **32 KiB** smaller.
* Amiga build now hangs instead of crashing.
`std::make_unique<T[]>(size)` always zero-initalizes the array.
C++20 has `std::make_unique_for_overwrite` to avoid that, while
older C++ versions can use the approach applied here.