mirror of
https://github.com/OpenTTD/OpenTTD.git
synced 2026-09-19 14:55:22 +00:00
Compare commits
303
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c56e08d5c3 | ||
|
|
e309ba1756 | ||
|
|
2692444f42 | ||
|
|
5b513abef0 | ||
|
|
de90358094 | ||
|
|
f58eac1d3a | ||
|
|
ec444f7315 | ||
|
|
b2da5d7ef9 | ||
|
|
1aca0b60a8 | ||
|
|
1e83380df9 | ||
|
|
a3f657f4f4 | ||
|
|
b33be554e2 | ||
|
|
704eea81ee | ||
|
|
b2bf655714 | ||
|
|
3e5d093336 | ||
|
|
02eb06ccd4 | ||
|
|
01377cbfd4 | ||
|
|
7de9eb4c2f | ||
|
|
ae1067023c | ||
|
|
fd0f4f95a4 | ||
|
|
0c0b63a6ec | ||
|
|
ecbe2aa17c | ||
|
|
177a60b87e | ||
|
|
bbd2c3e70e | ||
|
|
2838499563 | ||
|
|
5d18b7cca7 | ||
|
|
3d137db87f | ||
|
|
83d286383e | ||
|
|
0c2e7ec534 | ||
|
|
ddb284e074 | ||
|
|
79e679604a | ||
|
|
ee2b2ac12a | ||
|
|
34919f318f | ||
|
|
1c28b656a4 | ||
|
|
d1af18d1b6 | ||
|
|
bea6ddec8e | ||
|
|
18fc940ebf | ||
|
|
2e5440e1c6 | ||
|
|
1672405e76 | ||
|
|
f11e556d9c | ||
|
|
1ea8a4cab1 | ||
|
|
8cc4832744 | ||
|
|
de306de893 | ||
|
|
b28429e71a | ||
|
|
dc39225d60 | ||
|
|
141b4e5eec | ||
|
|
898eb92f3f | ||
|
|
b0ca968a34 | ||
|
|
2701268c3e | ||
|
|
ed04d336ed | ||
|
|
604525bb5d | ||
|
|
5232ea2f2d | ||
|
|
a5183042d8 | ||
|
|
28156aefe5 | ||
|
|
39c8ac1459 | ||
|
|
22f653480b | ||
|
|
91e5f72f41 | ||
|
|
07d3061b6f | ||
|
|
e5d5fdd4ac | ||
|
|
1c047a0f06 | ||
|
|
e17f17565a | ||
|
|
2237b6b973 | ||
|
|
96651d379a | ||
|
|
8d9b24cc1b | ||
|
|
333d091d47 | ||
|
|
d473c37f59 | ||
|
|
7a11bf6c17 | ||
|
|
262856ff4d | ||
|
|
a7755dbf7d | ||
|
|
c251f51ef1 | ||
|
|
43408dcf0e | ||
|
|
8a186962e5 | ||
|
|
e604110351 | ||
|
|
122287992c | ||
|
|
7f45e4a34b | ||
|
|
040aedcb92 | ||
|
|
d89d6831ba | ||
|
|
a2533911dd | ||
|
|
21c1e691ad | ||
|
|
39da062c0c | ||
|
|
5fcd0fbee7 | ||
|
|
4d4f8bff38 | ||
|
|
c3ee8ac11b | ||
|
|
1b1a16c53b | ||
|
|
4261255020 | ||
|
|
0f0fc477c9 | ||
|
|
77c82000e5 | ||
|
|
3a33cd64c9 | ||
|
|
713994a0d6 | ||
|
|
df55704e7d | ||
|
|
1b71d4c883 | ||
|
|
6b5173bfa5 | ||
|
|
ef223dca83 | ||
|
|
667a12c0c6 | ||
|
|
ada7ffaa73 | ||
|
|
c1604a75c6 | ||
|
|
9060a4a7ec | ||
|
|
cf584ea907 | ||
|
|
abf2843069 | ||
|
|
be4f099c00 | ||
|
|
bb165f1e79 | ||
|
|
987fab4bd6 | ||
|
|
9b34939052 | ||
|
|
8ef6fa58a8 | ||
|
|
42a9a05a09 | ||
|
|
b05468a4dd | ||
|
|
7bc1e32b78 | ||
|
|
3edd9a5a9b | ||
|
|
ce14e19d89 | ||
|
|
93141cbce1 | ||
|
|
c2bafefe50 | ||
|
|
f673985017 | ||
|
|
4c17039be7 | ||
|
|
285937137b | ||
|
|
868d7df408 | ||
|
|
3f04518f91 | ||
|
|
5ad9d5f048 | ||
|
|
f52d2e064a | ||
|
|
d328720ff5 | ||
|
|
30b5c8f68a | ||
|
|
00efe6a4ba | ||
|
|
5fc9137e71 | ||
|
|
0de95fb529 | ||
|
|
840b13567d | ||
|
|
4df104bc7d | ||
|
|
60f80826ac | ||
|
|
77ba2b244a | ||
|
|
19746b5c81 | ||
|
|
29f808ef00 | ||
|
|
4ecbb871d1 | ||
|
|
97951cfcf2 | ||
|
|
308e75d74d | ||
|
|
a6b1b3ac44 | ||
|
|
eced18224a | ||
|
|
d6848be640 | ||
|
|
b6f067cf36 | ||
|
|
252c239a14 | ||
|
|
368ade294a | ||
|
|
12208d1204 | ||
|
|
a68148f86f | ||
|
|
1bc8f44eab | ||
|
|
81d7025ab1 | ||
|
|
d84089248a | ||
|
|
16b08092b4 | ||
|
|
9fbb32fb7a | ||
|
|
de65913055 | ||
|
|
e6ee076dc3 | ||
|
|
9140a7ad4a | ||
|
|
9a6c4392ab | ||
|
|
cbf782c900 | ||
|
|
4a59aadb8b | ||
|
|
0753474676 | ||
|
|
2a33c65404 | ||
|
|
c4ba42cecb | ||
|
|
793663f0cd | ||
|
|
b7c4443215 | ||
|
|
1f981d5338 | ||
|
|
ec978b0e0a | ||
|
|
41dbebf7e9 | ||
|
|
259d75e2e5 | ||
|
|
f823a9af5d | ||
|
|
7f1946f996 | ||
|
|
9130c591dc | ||
|
|
0500bfdece | ||
|
|
d953f27dd9 | ||
|
|
bd41367e3c | ||
|
|
25ec12c62d | ||
|
|
ae35d8223f | ||
|
|
dda399faf3 | ||
|
|
c7cacf0752 | ||
|
|
7e7223d9b0 | ||
|
|
ea2f024c03 | ||
|
|
eef236e480 | ||
|
|
198893a04a | ||
|
|
66aea1f5d9 | ||
|
|
c0762f2c26 | ||
|
|
c40d482783 | ||
|
|
4ca37d0340 | ||
|
|
97e6800287 | ||
|
|
f9699cc6a1 | ||
|
|
c876c59d41 | ||
|
|
eb62295cc0 | ||
|
|
6892b8a463 | ||
|
|
9a02ac21e8 | ||
|
|
5298a18418 | ||
|
|
5b9f18d8fd | ||
|
|
d97005e31e | ||
|
|
3f2f61c49b | ||
|
|
162c629766 | ||
|
|
9bea75a8d1 | ||
|
|
150da36869 | ||
|
|
e065da15ff | ||
|
|
2d48e82bbb | ||
|
|
fa4b9819c0 | ||
|
|
7126fcafcc | ||
|
|
659208ab57 | ||
|
|
143af1098d | ||
|
|
68f5a8a0fd | ||
|
|
121df5b461 | ||
|
|
1d1c603494 | ||
|
|
af60d6b7cd | ||
|
|
fe31736981 | ||
|
|
80d0c7763a | ||
|
|
6b553caa74 | ||
|
|
2c48b1efb9 | ||
|
|
e3dfd59df0 | ||
|
|
0366278c9d | ||
|
|
808ae7f270 | ||
|
|
d1ec9f4897 | ||
|
|
922d38f1c0 | ||
|
|
e4620d5832 | ||
|
|
cf48f866eb | ||
|
|
3c30f962d4 | ||
|
|
3fb3006dff | ||
|
|
0ab5b6df1b | ||
|
|
a961e64928 | ||
|
|
9f8ac2aaa1 | ||
|
|
0c6de46b4c | ||
|
|
83f20c3375 | ||
|
|
85e6f020f9 | ||
|
|
83ce49f6cb | ||
|
|
44b51a94c5 | ||
|
|
f5e4bd1ed7 | ||
|
|
5303aa6516 | ||
|
|
5403257dca | ||
|
|
05e596661e | ||
|
|
e95f43a720 | ||
|
|
51af63cc9f | ||
|
|
8e89414d9e | ||
|
|
24333d76a9 | ||
|
|
ac51eab537 | ||
|
|
0f09b4b371 | ||
|
|
bf7bb3efaf | ||
|
|
9ba2e386ac | ||
|
|
21d9af637a | ||
|
|
788e112be1 | ||
|
|
bf70c61fb8 | ||
|
|
c18b3a8a04 | ||
|
|
8e08f1a3c5 | ||
|
|
8303b2d694 | ||
|
|
4d7e1385f9 | ||
|
|
d2a3f52257 | ||
|
|
01919af55b | ||
|
|
9c3f5bc375 | ||
|
|
0a9aa3d20b | ||
|
|
8db7db5569 | ||
|
|
d9d7f441db | ||
|
|
76265b8451 | ||
|
|
1310531139 | ||
|
|
0bd12558d4 | ||
|
|
bdbe305771 | ||
|
|
71ca79c6d5 | ||
|
|
afbe2d3070 | ||
|
|
f72a239b97 | ||
|
|
df20fed464 | ||
|
|
af1e9864a0 | ||
|
|
3f557fb673 | ||
|
|
36551ba6b5 | ||
|
|
11f46bc5f4 | ||
|
|
099df1054e | ||
|
|
d3d1de822d | ||
|
|
ef0d26f9f7 | ||
|
|
8a8ece49ec | ||
|
|
a01a2f8401 | ||
|
|
d0dcd1b134 | ||
|
|
a5430717b1 | ||
|
|
c367b10bde | ||
|
|
2934eca24a | ||
|
|
02becd50c5 | ||
|
|
3ba0706a5c | ||
|
|
1acbb1c654 | ||
|
|
6f6551c08d | ||
|
|
b4d16d319f | ||
|
|
8e637cefed | ||
|
|
5923d105ec | ||
|
|
a76ba0d3d4 | ||
|
|
b7d07252e7 | ||
|
|
f8af6bbc2f | ||
|
|
8b83bac31f | ||
|
|
b02242d5fc | ||
|
|
4344ffb7a0 | ||
|
|
4e9645e9d0 | ||
|
|
947767a2ff | ||
|
|
4b93bd74ef | ||
|
|
061e5c9cd3 | ||
|
|
5b3b7995bb | ||
|
|
3666eb23a1 | ||
|
|
f9e6b8b7dd | ||
|
|
2a6a65662d | ||
|
|
b7e693ced6 | ||
|
|
b9986cdadf | ||
|
|
dc87cd3d7a | ||
|
|
8ca99f96ee | ||
|
|
790a6903af | ||
|
|
98dfc7376c | ||
|
|
cc92e3d421 | ||
|
|
42fe1133ad | ||
|
|
fc0ad4bb0a | ||
|
|
5bb87d39b7 | ||
|
|
f8ad1a4999 | ||
|
|
f0a1b507fe | ||
|
|
2f4ae80226 | ||
|
|
11e713ce9a |
@@ -105,4 +105,4 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Check annotations
|
||||
uses: OpenTTD/actions/annotation-check@v6
|
||||
uses: OpenTTD/actions/annotation-check@v7
|
||||
|
||||
@@ -14,30 +14,23 @@ jobs:
|
||||
container:
|
||||
# If you change this version, change the numbers in the cache step,
|
||||
# .github/workflows/preview-build.yml (2x) and os/emscripten/Dockerfile too.
|
||||
image: emscripten/emsdk:3.1.57
|
||||
image: emscripten/emsdk:6.0.1
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Fix dubious ownership
|
||||
run: |
|
||||
git config --global --add safe.directory ${GITHUB_WORKSPACE}
|
||||
|
||||
- name: Update to modern GCC
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get install -y gcc-12 g++-12
|
||||
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-12 100
|
||||
update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-12 100
|
||||
|
||||
- name: Setup cache
|
||||
uses: actions/cache@v5
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
# If you change this version, change the numbers in the image configuration step,
|
||||
# .github/workflows/preview-build.yml (2x) and os/emscripten/Dockerfile too.
|
||||
path: /emsdk/upstream/emscripten/cache
|
||||
key: 3.1.57-${{ runner.os }}
|
||||
key: 6.0.1-${{ runner.os }}
|
||||
|
||||
- name: Add liblzma support
|
||||
run: |
|
||||
|
||||
@@ -23,18 +23,18 @@ jobs:
|
||||
linux:
|
||||
name: CI
|
||||
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CC: ${{ inputs.compiler }}
|
||||
CXX: ${{ inputs.cxxcompiler }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Setup vcpkg
|
||||
id: vcpkg
|
||||
uses: OpenTTD/actions/setup-vcpkg@v6
|
||||
uses: OpenTTD/actions/setup-vcpkg@v7
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
@@ -54,6 +54,7 @@ jobs:
|
||||
libogg-dev \
|
||||
libopus-dev \
|
||||
libopusfile-dev \
|
||||
libsoxr-dev \
|
||||
${{ inputs.libraries }} \
|
||||
zlib1g-dev \
|
||||
# EOF
|
||||
|
||||
@@ -32,11 +32,11 @@ jobs:
|
||||
xcode-version: latest-stable
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Setup vcpkg
|
||||
id: vcpkg
|
||||
uses: OpenTTD/actions/setup-vcpkg@v6
|
||||
uses: OpenTTD/actions/setup-vcpkg@v7
|
||||
|
||||
- name: Install OpenGFX
|
||||
run: |
|
||||
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Setup MSYS2
|
||||
uses: msys2/setup-msys2@v2
|
||||
@@ -41,6 +41,7 @@ jobs:
|
||||
libogg:p
|
||||
opus:p
|
||||
opusfile:p
|
||||
libsoxr:p
|
||||
|
||||
- name: Install OpenGFX
|
||||
shell: bash
|
||||
|
||||
@@ -55,4 +55,4 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Check annotations
|
||||
uses: OpenTTD/actions/annotation-check@v6
|
||||
uses: OpenTTD/actions/annotation-check@v7
|
||||
|
||||
@@ -18,11 +18,11 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Setup vcpkg
|
||||
id: vcpkg
|
||||
uses: OpenTTD/actions/setup-vcpkg@v6
|
||||
uses: OpenTTD/actions/setup-vcpkg@v7
|
||||
|
||||
- name: Install OpenGFX
|
||||
shell: bash
|
||||
|
||||
@@ -25,11 +25,11 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Setup vcpkg
|
||||
id: vcpkg
|
||||
uses: OpenTTD/actions/setup-vcpkg@v6
|
||||
uses: OpenTTD/actions/setup-vcpkg@v7
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
@@ -49,6 +49,7 @@ jobs:
|
||||
libopus-dev \
|
||||
libopusfile-dev \
|
||||
libsdl2-dev \
|
||||
libsoxr-dev \
|
||||
zlib1g-dev \
|
||||
# EOF
|
||||
|
||||
@@ -75,7 +76,7 @@ jobs:
|
||||
echo "::endgroup::"
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v4
|
||||
uses: github/codeql-action/init@v4.37.9
|
||||
with:
|
||||
languages: cpp
|
||||
config-file: ./.github/codeql/codeql-config.yml
|
||||
@@ -91,7 +92,7 @@ jobs:
|
||||
echo "::endgroup::"
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v4
|
||||
uses: github/codeql-action/analyze@v4.37.9
|
||||
with:
|
||||
category: /language:cpp
|
||||
upload: False
|
||||
@@ -109,6 +110,6 @@ jobs:
|
||||
output: sarif-results/cpp.sarif
|
||||
|
||||
- name: Upload results
|
||||
uses: github/codeql-action/upload-sarif@v4
|
||||
uses: github/codeql-action/upload-sarif@v4.37.9
|
||||
with:
|
||||
sarif_file: sarif-results/cpp.sarif
|
||||
|
||||
@@ -14,12 +14,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 4
|
||||
|
||||
- name: Get pull-request commits
|
||||
uses: OpenTTD/actions/checkout-pull-request@v6
|
||||
uses: OpenTTD/actions/checkout-pull-request@v7
|
||||
|
||||
- name: Check commits
|
||||
uses: OpenTTD/OpenTTD-git-hooks@main
|
||||
|
||||
@@ -14,12 +14,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 4
|
||||
|
||||
- name: Get pull-request commits
|
||||
uses: OpenTTD/actions/checkout-pull-request@v6
|
||||
uses: OpenTTD/actions/checkout-pull-request@v7
|
||||
|
||||
- name: Install Doxygen
|
||||
uses: ./.github/install-doxygen
|
||||
|
||||
@@ -14,12 +14,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 4
|
||||
|
||||
- name: Get pull-request commits
|
||||
uses: OpenTTD/actions/checkout-pull-request@v6
|
||||
uses: OpenTTD/actions/checkout-pull-request@v7
|
||||
|
||||
- name: Check descriptions of source files
|
||||
run: |
|
||||
|
||||
@@ -11,11 +11,11 @@ jobs:
|
||||
container:
|
||||
# If you change this version, change the numbers in the cache step,
|
||||
# .github/workflows/ci-emscripten.yml (2x) and os/emscripten/Dockerfile too.
|
||||
image: emscripten/emsdk:3.1.57
|
||||
image: emscripten/emsdk:6.0.1
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
@@ -24,20 +24,13 @@ jobs:
|
||||
git config --global --add safe.directory ${GITHUB_WORKSPACE}
|
||||
git checkout -b pr${{ github.event.pull_request.number }}
|
||||
|
||||
- name: Update to modern GCC
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get install -y gcc-12 g++-12
|
||||
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-12 100
|
||||
update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-12 100
|
||||
|
||||
- name: Setup cache
|
||||
uses: actions/cache@v5
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: /emsdk/upstream/emscripten/cache
|
||||
# If you change this version, change the numbers in the image configuration step,
|
||||
# .github/workflows/ci-emscripten.yml (2x) and os/emscripten/Dockerfile too.
|
||||
key: 3.1.57-${{ runner.os }}
|
||||
key: 6.0.1-${{ runner.os }}
|
||||
|
||||
- name: Add liblzma support
|
||||
run: |
|
||||
|
||||
@@ -41,7 +41,7 @@ jobs:
|
||||
echo "number=$(cat pr/number)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Publish preview
|
||||
uses: cloudflare/wrangler-action@v3
|
||||
uses: cloudflare/wrangler-action@v4
|
||||
with:
|
||||
apiToken: ${{ secrets.PREVIEW_CLOUDFLARE_API_TOKEN }}
|
||||
accountId: ${{ secrets.PREVIEW_CLOUDFLARE_ACCOUNT_ID }}
|
||||
|
||||
@@ -114,7 +114,7 @@ jobs:
|
||||
|
||||
- name: Setup vcpkg
|
||||
id: vcpkg
|
||||
uses: OpenTTD/actions/setup-vcpkg@v6
|
||||
uses: OpenTTD/actions/setup-vcpkg@v7
|
||||
with:
|
||||
vcpkg-location: /vcpkg
|
||||
mono-install-command: 'yum install -y mono-complete'
|
||||
|
||||
@@ -39,7 +39,7 @@ jobs:
|
||||
|
||||
- name: Setup vcpkg
|
||||
id: vcpkg
|
||||
uses: OpenTTD/actions/setup-vcpkg@v6
|
||||
uses: OpenTTD/actions/setup-vcpkg@v7
|
||||
|
||||
- name: Install dependencies
|
||||
env:
|
||||
|
||||
@@ -30,14 +30,14 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout (Release)
|
||||
if: github.event_name == 'release'
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
# We generate a changelog; for this we need the full git log.
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Checkout (Manual)
|
||||
if: github.event_name == 'workflow_dispatch'
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ github.event.inputs.ref }}
|
||||
# We generate a changelog; for this we need the full git log.
|
||||
@@ -45,7 +45,7 @@ jobs:
|
||||
|
||||
- name: Checkout (Trigger)
|
||||
if: github.event_name == 'repository_dispatch'
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ github.event.client_payload.ref }}
|
||||
# We generate a changelog; for this we need the full git log.
|
||||
|
||||
@@ -47,7 +47,7 @@ jobs:
|
||||
|
||||
- name: Setup vcpkg
|
||||
id: vcpkg
|
||||
uses: OpenTTD/actions/setup-vcpkg@v6
|
||||
uses: OpenTTD/actions/setup-vcpkg@v7
|
||||
|
||||
- name: Install dependencies
|
||||
shell: bash
|
||||
|
||||
@@ -14,7 +14,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Check for finding script functions that require company/deity mode enforcement/checks
|
||||
run: |
|
||||
|
||||
@@ -14,7 +14,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Check for unused strings
|
||||
run: |
|
||||
|
||||
@@ -88,7 +88,7 @@ jobs:
|
||||
- prepare
|
||||
|
||||
name: Publish bundles
|
||||
uses: OpenTTD/actions/.github/workflows/rw-cdn-upload.yml@v6
|
||||
uses: OpenTTD/actions/.github/workflows/rw-cdn-upload.yml@v7
|
||||
secrets:
|
||||
CDN_SIGNING_KEY: ${{ secrets.CDN_SIGNING_KEY }}
|
||||
DEPLOYMENT_APP_ID: ${{ secrets.DEPLOYMENT_APP_ID }}
|
||||
@@ -103,7 +103,7 @@ jobs:
|
||||
- prepare
|
||||
|
||||
name: Publish symbols
|
||||
uses: OpenTTD/actions/.github/workflows/rw-symbols-upload.yml@v6
|
||||
uses: OpenTTD/actions/.github/workflows/rw-symbols-upload.yml@v7
|
||||
secrets:
|
||||
SYMBOLS_SIGNING_KEY: ${{ secrets.SYMBOLS_SIGNING_KEY }}
|
||||
with:
|
||||
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
path: openttd-windows-store
|
||||
|
||||
- name: Configure Microsoft Store CLI
|
||||
uses: microsoft/microsoft-store-apppublisher@v1.3
|
||||
uses: microsoft/microsoft-store-apppublisher@v1.4
|
||||
|
||||
- name: Reconfigure store credentials
|
||||
run: msstore reconfigure `
|
||||
|
||||
+3
-1
@@ -156,6 +156,7 @@ if(NOT OPTION_DEDICATED)
|
||||
endif()
|
||||
endif()
|
||||
find_package(OpusFile)
|
||||
find_package(Soxr)
|
||||
endif()
|
||||
if(APPLE)
|
||||
enable_language(OBJCXX)
|
||||
@@ -330,6 +331,7 @@ if(NOT OPTION_DEDICATED)
|
||||
link_package(ICU_I18N TARGET ICU::i18n)
|
||||
link_package(ICU_UC TARGET ICU::uc)
|
||||
link_package(OpusFile TARGET OpusFile::opusfile)
|
||||
link_package(Soxr TARGET Soxr::soxr)
|
||||
|
||||
if(SDL2_FOUND AND OPENGL_FOUND AND UNIX)
|
||||
# SDL2 dynamically loads OpenGL if needed, so do not link to OpenGL when
|
||||
@@ -370,7 +372,7 @@ if(EMSCRIPTEN)
|
||||
add_definitions(-s DISABLE_EXCEPTION_CATCHING=0)
|
||||
|
||||
# Export functions to Javascript.
|
||||
target_link_libraries(WASM::WASM INTERFACE "-s EXPORTED_FUNCTIONS='[\"_main\", \"_em_openttd_add_server\"]' -s EXPORTED_RUNTIME_METHODS='[\"cwrap\"]'")
|
||||
target_link_libraries(WASM::WASM INTERFACE "-s EXPORTED_FUNCTIONS='[\"_main\", \"_em_openttd_add_server\"]' -s EXPORTED_RUNTIME_METHODS='[\"cwrap\", \"HEAPU8\"]'")
|
||||
|
||||
# Preload all the files we generate during build.
|
||||
# As we do not compile with FreeType / FontConfig, we also have no way to
|
||||
|
||||
@@ -12,6 +12,7 @@ What is simple to some might appear very complicated to others. Documentation he
|
||||
* Use Foo() instead of Foo(void).
|
||||
* Prefer using "const" for reference and compound parameters when appropriate.
|
||||
* If a member function can be a const function, make it so.
|
||||
* Order of qualifiers is `static inline` / `static constexpr`, don't use `inline` with `constexpr`.
|
||||
```c++
|
||||
void ThisIsAFunction()
|
||||
{
|
||||
|
||||
+170
-97
@@ -1,104 +1,177 @@
|
||||
## 16.x
|
||||
|
||||
### 16.0-beta3 (2026-09-19)
|
||||
|
||||
- Feature: Double-ended ships (#16002)
|
||||
- Feature: [Script] AI API to remove rail depot (#15933)
|
||||
- Feature: Create new folders from the save dialog (#15730)
|
||||
- Feature: Screensaver Mode (#15350)
|
||||
- Add: Use LibSoxr for high quality sample-rate conversion (#15924)
|
||||
- Add: Allow placing/erasing rough terrain in scenario editor (#15624)
|
||||
- Add: Show train length in reworked vehicle info panel (#15389)
|
||||
- Add: [NewGRF] Number of nearby stations for towns (#15200)
|
||||
- Add: [NewGRF] Town additional information (#15198)
|
||||
- Add: [NewGRF] Nearby tile info for towns (#15194)
|
||||
- Add: Add water and coastal rock tiles (#15869)
|
||||
- Add: Place rocks randomly around lighthouses (#15869)
|
||||
- Change: Allow orders and timetable windows to be smaller (#16008)
|
||||
- Change: Allow font size to be changed with default truetype font (#16000)
|
||||
- Change: Allow admin to join any company in all interfaces (#15992)
|
||||
- Change: Generate rough tiles as clusters, like rocks (#15963)
|
||||
- Change: [NewGRF] Remove airport tile ID hole at 0xFF (#15956)
|
||||
- Change: [NewGRF] Remove object ID hole at 0xFF (#15956)
|
||||
- Change: [NewGRF] Remove industry tile ID hole at 0xFF (#15956)
|
||||
- Change: Move small map buttons to side of window (#15885)
|
||||
- Change: Update wording of force unload order (#15880)
|
||||
- Change: New coast and toyland rock overlay sprites (#15869)
|
||||
- Change: Lowering tiles when terraforming makes rocky slopes (#15822)
|
||||
- Change: Limit purchase list rows to 1.5x original design height (#15749)
|
||||
- Change: Clip content in purchase list to each row (#15749)
|
||||
- Change: Account for driving cabs in driving backwards conditional order (#15494)
|
||||
- Change: [NewGRF] Ensure modflags bit 8 respects old behavior when train is driving backwards (#15485)
|
||||
- Change: Allow road vehicles to overtake through junctions between one-way roads (#15445)
|
||||
- Change: Use new game setting for disable_elrails when loading very old save (#14481)
|
||||
- Change: [NewGRF] Remove per-grf industry tile limit (#12183)
|
||||
- Fix #15824: Game crash when truncating cargo of crashed vehicle (#16005)
|
||||
- Fix: Reducing a vehicle's cargo capacity incorrectly truncated the cargo. (#16004)
|
||||
- Fix #15506: [Script] Avoid ternary signed/unsigned conversion when returning literal -1 (#16001)
|
||||
- Fix #15759: Inconsistency in disabled electric rails compatibility (#15994)
|
||||
- Fix #15990: Game crash when clearing up crashed train with last wagon in depot (#15991)
|
||||
- Fix #15985: Incorrect train station area after adding to a station (#15986)
|
||||
- Fix: Don't require glyphs for non-breaking space characters (#15982)
|
||||
- Fix #15863: Train should not clear path reservation under the other train that crashed into its front (#15980)
|
||||
- Fix #15636: Allow shift and ctrl modifiers in hotkeys (#15976)
|
||||
- Fix: [NewGRF] Validate airport tile layouts (#15970)
|
||||
- Fix: [NewGRF] Improve industry tile layout validation (#15970)
|
||||
- Fix: Wrong button size in Bootstrap query window if game window resized (#15968)
|
||||
- Fix #15233: Don't require glyphs for various whitespace characters (#15967)
|
||||
- Fix: Wrong category for some base set debug messages (#15965)
|
||||
- Fix #15961: Don't pass a temporary object to BreakIterator::setText (#15962)
|
||||
- Fix: Autoclean empty time only checked for connected clients at month boundary (#15954)
|
||||
- Fix: Invalidate/update vehicle caches when vehicle is marked dirty (#15946)
|
||||
- Fix: Random company colours choice was reversed (#15944)
|
||||
- Fix: Properly disallow duplicate company names (#15911)
|
||||
- Fix #15905: Dual-headed engines showed incorrect capacity when sorting (#15907)
|
||||
- Fix: Potential off-by-one out of bounds read during saving (#15903)
|
||||
- Fix: Coast tiles were shown as water tiles in small map (#15883)
|
||||
- Fix: Limit vehicle reliability to the model's current maximum reliability (#15879)
|
||||
- Fix: Rail depot overbuild did not handle associated reservation (#15860)
|
||||
- Fix #15849: Rivers no longer fill small seas with original land gen (#15852)
|
||||
- Fix: Player-placed house protection for houses should override the callback (#14408)
|
||||
|
||||
### 16.0-beta2 (2026-07-12)
|
||||
|
||||
- Feature: Allow bridges over depots (#15836)
|
||||
- Feature: Increase maximum number of vehicles per type to 10,000 (#15810)
|
||||
- Feature: Add and remove whole classes to picker collections (#15808)
|
||||
- Feature: Station list can be filtered by name (#15772)
|
||||
- Change: Use "bridge ... too low" message for bridgeable objects (#15838)
|
||||
- Fix: Use meaningful tooltips for graph range toggle buttons (#15842)
|
||||
- Fix #15826: Exclude allow any/all options for AI companies (#15834)
|
||||
- Fix #7992: Fix for catenary road and tram catenary sprites not being drawn on bridges (#15811)
|
||||
- Fix #15784: Crash due to incorrect road build toolbar when switching road tram types (#15789)
|
||||
- Fix: [NewGRF] Make 'signals on traffic side' consistent with explicit settings (#15661)
|
||||
- Fix: [Win32] Explicitly initialize COM in Win32 video driver (#15553)
|
||||
|
||||
### 16.0-beta1 (2026-06-25)
|
||||
|
||||
Feature: Add default road and tram selection (#15585)
|
||||
Feature: Trains with an engine on the rear can drive backwards when reversing (#15379)
|
||||
Feature: Add worldgen setting for average height of terrain (#14989)
|
||||
Feature: Add text filter to dropdown lists (#14842)
|
||||
Feature: User-defined collections of saved items in the picker window (#14813)
|
||||
Feature: Configurable sign text colors in scenario editor (#14743)
|
||||
Feature: Allow placing an area of 1x1 houses in scenario editor (#14708)
|
||||
Feature: Scale cargo payment aging rate (#14635)
|
||||
Feature: Support automatic detection of data from Atari's Transport Tycoon Deluxe re-release (#15483)
|
||||
Add: [NewGRF] Implement custom waypoint layouts by callback 24 (#15616)
|
||||
Add: List 'Place object' in landscaping dropdown (#15609)
|
||||
Add: Setting to disable aircraft range limit (#15433)
|
||||
Add: Show maximum reliability in vehicle info (#15401)
|
||||
Add: Lower the Send To Depot button when a vehicle is on its way to one (#15397)
|
||||
Add: Setting to disallow train magic flip, and reverse at reduced speed (#15391)
|
||||
Add: [NewGRF] Variable for when a train is driving backwards (#15379)
|
||||
Add: [NewGRF] Flag to allow unpowered wagon to lead train when backing up (#15379)
|
||||
Add: [NewGRF] Station flag to divide cargo by area instead of perimeter (#15253)
|
||||
Add: Company allow-list can be set to allow anyone (#15204)
|
||||
Add: Record history of cargo delivered to towns (#15184)
|
||||
Add: Show additional vehicle details based on sort criteria (#15158)
|
||||
Add: Setting to control minimum distance between towns (#14893)
|
||||
Change: Selecting Rail/Roadtype updates build toolbar instead of closing and reopening (#15589)
|
||||
Change: Default setting to review orders excludes stopped vehicles (#15565)
|
||||
Change: Most used rail type takes ownership into account (#15489)
|
||||
Change: Test font for eligibility before adding as fallback (#15412)
|
||||
Change: Clarify max age shown in vehicle info window (#15403)
|
||||
Change: Show "Delete All" in order window delete button when applicable (#15370)
|
||||
Change: Make continuation error messages consistent (#15328)
|
||||
Change: Distinguish between 'Flat land required' and 'Land sloped in wrong direction' for building depots (#15327)
|
||||
Change: Allow subsidies with CargoDist (#15189)
|
||||
Change: Removing river tiles reduces local authority rating (#15180)
|
||||
Change: Protect rivers from removal when terraforming (#15176)
|
||||
Change: [Script] Reformat callstack output (#15171)
|
||||
Change: Apply slightly more padding to image-text buttons (#15077)
|
||||
Change: [NewGRF] Display rail and road type speed limit text in yellow (#15076)
|
||||
Change: Make smallmap show infinite water, if enabled (#15041)
|
||||
Change: Add support for next/previous/first/last rail/road/tram type hotkeys (#15028)
|
||||
Change: Allow rocks on desert tiles (#14979)
|
||||
Change: [Script] Include Array/PriorityQueye/ScriptList contents in script memory allocation total (#14954)
|
||||
Change: [Script] Various ScriptList methods are now suspendable (#14943, #14762)
|
||||
Change: Improve generation of coasts at map edges (#14868)
|
||||
Change: Show only selected badge in badge filter dropdown buttons (#14855)
|
||||
Change: River springs must be surrounded by hills (#14845)
|
||||
Change: Vehicles loading at stations don't lose reliability (#14841)
|
||||
Change: Generate lighthouses along coasts and near towns (#14828)
|
||||
Change: Transmitter object only spawns after original base year (#14786)
|
||||
Change: Share one window for engine preview pop ups (#14703)
|
||||
Fix: [NewGRF] Town name language incorrectly decoded (#15691)
|
||||
Fix #15606: Undefined behaviour may cause buttons to be invisible (#15686)
|
||||
Fix #14975: Show correct tile for tunnel error message (#15660)
|
||||
Fix: [NewGRF] Incorrect language IDs passed to TranslateTTDPatchCodes (#15655)
|
||||
Fix: Scenario editor random industry generation (#15626)
|
||||
Fix: [NewGRF] Ignore blocked waypoint tiles (#15620)
|
||||
Fix: [NewGRF] Pylons and no-wires flags were ignored for waypoint tiles (#15619)
|
||||
Fix: Dedicated server signal handling for SIGTERM/SIGINT/SIGQUIT (#15607)
|
||||
Fix: [NewGRF] Potential out-of-bounds read when performing GRM (#15600)
|
||||
Fix: Badge offsets not ignored when determining width (#15588)
|
||||
Fix: Account for NewGRF's global train width when drawing dual-head engines (#15587)
|
||||
Fix: Station list facility buttons do not produce click sound (#15569)
|
||||
Fix #15495: Fix incorrectly built default waypoints (#15562)
|
||||
Fix #15495: Unable to build bridge over default waypoints (#15562)
|
||||
Fix #15235: Make GameScripts obey town road construction setting (#15559)
|
||||
Fix: Crash when loading crash save with no viewport coordinates (#15550)
|
||||
Fix #15520: Fix viewport snap back on stop following vehicle (#15520) (#15531)
|
||||
Fix: Buttons for choosing engine in preview window show for single engine (#15514)
|
||||
Fix #15511: Vehicle passed to commands must be a company buildable type (#15512)
|
||||
Fix #15497: [Script] ScriptController::Break not pausing in TestMode (#15498)
|
||||
Fix: Coordinate transformation for JSON town placement when anticlockwise (#15490)
|
||||
Fix: NewGRF debug handler for towns in wrong place since badges (#15467)
|
||||
Fix: Object id overrides were not reset between games (#15465)
|
||||
Fix: Debug saveload errors were clobbered (#15452)
|
||||
Fix: Refresh client list when client renames (#15439)
|
||||
Fix #15428: [Fluidsynth] Treat configured synth.gain as maximum instead of hardcoded value (#15429)
|
||||
Fix: Refresh string width cache for all loaded fonts (#15427)
|
||||
Fix: Typo in Hungarian town name suffix ("kak" -> "lak") (#15421)
|
||||
Fix: [NewGRF] Variable 0x69 has not been added for waypoints (#15396)
|
||||
Fix: Dropdown text filter could interfere with hotkeys after closing (#15395)
|
||||
Fix: Rejecting or accepting engine preview incorrectly closed preview window (#15378)
|
||||
Fix #15318: Nonsensical error message when trying to send aircraft to hangar with no usable airports (#15334)
|
||||
Fix #15234: Null pointer dereference opening sign edit window when sign 0 does not exist (#15236)
|
||||
Fix: [GS] Docs are missing or do not match the code (#15230)
|
||||
Fix: Off by one and redundant logic in snowy road checks (#15214)
|
||||
Fix #15137: Roads built on steep slopes at the minimum snow level height have inconsistent snowiness (#15190)
|
||||
Fix: Station view window fold/unfold not refreshing scrollbar (#15187)
|
||||
Fix: Use consistent description for invalid orders (#15177)
|
||||
Fix: [Script] Give GetPrimary/SecondaryLiveryColour preconditions (#15169)
|
||||
Fix: Cocoa video driver did not register (#15145)
|
||||
Fix: MacOS version detection was broken (#15145)
|
||||
Fix #13600: Make terraform click+draggable in scenario editor (#15135)
|
||||
Fix: [Script] Map some error strings to existing errors (#15113)
|
||||
Fix: Allow to build buoys at (0x0) (#14983)
|
||||
Fix #14610: Do not treat aircraft with only depot orders as having valid orders (#14961)
|
||||
Fix #12937: Allow the computer to go to sleep while the game is paused (#14948)
|
||||
Fix: Company query popups do not update in multiplayer (#14947)
|
||||
Fix #14892: Potential crash when logging fonts for survey (#14896)
|
||||
Fix #14827: Store random trigger information per-tile (#14830)
|
||||
- Feature: Add default road and tram selection (#15585)
|
||||
- Feature: Trains with an engine on the rear can drive backwards when reversing (#15379)
|
||||
- Feature: Add worldgen setting for average height of terrain (#14989)
|
||||
- Feature: Add text filter to dropdown lists (#14842)
|
||||
- Feature: User-defined collections of saved items in the picker window (#14813)
|
||||
- Feature: Configurable sign text colors in scenario editor (#14743)
|
||||
- Feature: Allow placing an area of 1x1 houses in scenario editor (#14708)
|
||||
- Feature: Scale cargo payment aging rate (#14635)
|
||||
- Feature: Support automatic detection of data from Atari's Transport Tycoon Deluxe re-release (#15483)
|
||||
- Add: [NewGRF] Implement custom waypoint layouts by callback 24 (#15616)
|
||||
- Add: List 'Place object' in landscaping dropdown (#15609)
|
||||
- Add: Setting to disable aircraft range limit (#15433)
|
||||
- Add: Show maximum reliability in vehicle info (#15401)
|
||||
- Add: Lower the Send To Depot button when a vehicle is on its way to one (#15397)
|
||||
- Add: Setting to disallow train magic flip, and reverse at reduced speed (#15391)
|
||||
- Add: [NewGRF] Variable for when a train is driving backwards (#15379)
|
||||
- Add: [NewGRF] Flag to allow unpowered wagon to lead train when backing up (#15379)
|
||||
- Add: [NewGRF] Station flag to divide cargo by area instead of perimeter (#15253)
|
||||
- Add: Company allow-list can be set to allow anyone (#15204)
|
||||
- Add: Record history of cargo delivered to towns (#15184)
|
||||
- Add: Show additional vehicle details based on sort criteria (#15158)
|
||||
- Add: Setting to control minimum distance between towns (#14893)
|
||||
- Change: Selecting Rail/Roadtype updates build toolbar instead of closing and reopening (#15589)
|
||||
- Change: Default setting to review orders excludes stopped vehicles (#15565)
|
||||
- Change: Most used rail type takes ownership into account (#15489)
|
||||
- Change: Test font for eligibility before adding as fallback (#15412)
|
||||
- Change: Clarify max age shown in vehicle info window (#15403)
|
||||
- Change: Show "Delete All" in order window delete button when applicable (#15370)
|
||||
- Change: Make continuation error messages consistent (#15328)
|
||||
- Change: Distinguish between 'Flat land required' and 'Land sloped in wrong direction' for building depots (#15327)
|
||||
- Change: Allow subsidies with CargoDist (#15189)
|
||||
- Change: Removing river tiles reduces local authority rating (#15180)
|
||||
- Change: Protect rivers from removal when terraforming (#15176)
|
||||
- Change: [Script] Reformat callstack output (#15171)
|
||||
- Change: Apply slightly more padding to image-text buttons (#15077)
|
||||
- Change: [NewGRF] Display rail and road type speed limit text in yellow (#15076)
|
||||
- Change: Make smallmap show infinite water, if enabled (#15041)
|
||||
- Change: Add support for next/previous/first/last rail/road/tram type hotkeys (#15028)
|
||||
- Change: Allow rocks on desert tiles (#14979)
|
||||
- Change: [Script] Include Array/PriorityQueye/ScriptList contents in script memory allocation total (#14954)
|
||||
- Change: [Script] Various ScriptList methods are now suspendable (#14943, #14762)
|
||||
- Change: Improve generation of coasts at map edges (#14868)
|
||||
- Change: Show only selected badge in badge filter dropdown buttons (#14855)
|
||||
- Change: River springs must be surrounded by hills (#14845)
|
||||
- Change: Vehicles loading at stations don't lose reliability (#14841)
|
||||
- Change: Generate lighthouses along coasts and near towns (#14828)
|
||||
- Change: Transmitter object only spawns after original base year (#14786)
|
||||
- Change: Share one window for engine preview pop ups (#14703)
|
||||
- Fix: [NewGRF] Town name language incorrectly decoded (#15691)
|
||||
- Fix #15606: Undefined behaviour may cause buttons to be invisible (#15686)
|
||||
- Fix #14975: Show correct tile for tunnel error message (#15660)
|
||||
- Fix: [NewGRF] Incorrect language IDs passed to TranslateTTDPatchCodes (#15655)
|
||||
- Fix: Scenario editor random industry generation (#15626)
|
||||
- Fix: [NewGRF] Ignore blocked waypoint tiles (#15620)
|
||||
- Fix: [NewGRF] Pylons and no-wires flags were ignored for waypoint tiles (#15619)
|
||||
- Fix: Dedicated server signal handling for SIGTERM/SIGINT/SIGQUIT (#15607)
|
||||
- Fix: [NewGRF] Potential out-of-bounds read when performing GRM (#15600)
|
||||
- Fix: Badge offsets not ignored when determining width (#15588)
|
||||
- Fix: Account for NewGRF's global train width when drawing dual-head engines (#15587)
|
||||
- Fix: Station list facility buttons do not produce click sound (#15569)
|
||||
- Fix #15495: Fix incorrectly built default waypoints (#15562)
|
||||
- Fix #15495: Unable to build bridge over default waypoints (#15562)
|
||||
- Fix #15235: Make GameScripts obey town road construction setting (#15559)
|
||||
- Fix: Crash when loading crash save with no viewport coordinates (#15550)
|
||||
- Fix #15520: Fix viewport snap back on stop following vehicle (#15520) (#15531)
|
||||
- Fix: Buttons for choosing engine in preview window show for single engine (#15514)
|
||||
- Fix #15511: Vehicle passed to commands must be a company buildable type (#15512)
|
||||
- Fix #15497: [Script] ScriptController::Break not pausing in TestMode (#15498)
|
||||
- Fix: Coordinate transformation for JSON town placement when anticlockwise (#15490)
|
||||
- Fix: NewGRF debug handler for towns in wrong place since badges (#15467)
|
||||
- Fix: Object id overrides were not reset between games (#15465)
|
||||
- Fix: Debug saveload errors were clobbered (#15452)
|
||||
- Fix: Refresh client list when client renames (#15439)
|
||||
- Fix #15428: [Fluidsynth] Treat configured synth.gain as maximum instead of hardcoded value (#15429)
|
||||
- Fix: Refresh string width cache for all loaded fonts (#15427)
|
||||
- Fix: Typo in Hungarian town name suffix ("kak" -> "lak") (#15421)
|
||||
- Fix: [NewGRF] Variable 0x69 has not been added for waypoints (#15396)
|
||||
- Fix: Dropdown text filter could interfere with hotkeys after closing (#15395)
|
||||
- Fix: Rejecting or accepting engine preview incorrectly closed preview window (#15378)
|
||||
- Fix #15318: Nonsensical error message when trying to send aircraft to hangar with no usable airports (#15334)
|
||||
- Fix #15234: Null pointer dereference opening sign edit window when sign 0 does not exist (#15236)
|
||||
- Fix: [GS] Docs are missing or do not match the code (#15230)
|
||||
- Fix: Off by one and redundant logic in snowy road checks (#15214)
|
||||
- Fix #15137: Roads built on steep slopes at the minimum snow level height have inconsistent snowiness (#15190)
|
||||
- Fix: Station view window fold/unfold not refreshing scrollbar (#15187)
|
||||
- Fix: Use consistent description for invalid orders (#15177)
|
||||
- Fix: [Script] Give GetPrimary/SecondaryLiveryColour preconditions (#15169)
|
||||
- Fix: Cocoa video driver did not register (#15145)
|
||||
- Fix: MacOS version detection was broken (#15145)
|
||||
- Fix #13600: Make terraform click+draggable in scenario editor (#15135)
|
||||
- Fix: [Script] Map some error strings to existing errors (#15113)
|
||||
- Fix: Allow to build buoys at (0x0) (#14983)
|
||||
- Fix #14610: Do not treat aircraft with only depot orders as having valid orders (#14961)
|
||||
- Fix #12937: Allow the computer to go to sleep while the game is paused (#14948)
|
||||
- Fix: Company query popups do not update in multiplayer (#14947)
|
||||
- Fix #14892: Potential crash when logging fonts for survey (#14896)
|
||||
- Fix #14827: Store random trigger information per-tile (#14830)
|
||||
|
||||
## 15.x
|
||||
|
||||
|
||||
@@ -56,11 +56,6 @@ macro(compile_flags)
|
||||
# This flag disables the broken optimisation to work around the bug
|
||||
add_compile_options(/d2ssa-rse-)
|
||||
endif()
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
add_compile_options(
|
||||
-Wno-multichar
|
||||
)
|
||||
endif()
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||
add_compile_options(
|
||||
-W
|
||||
@@ -78,9 +73,6 @@ macro(compile_flags)
|
||||
-Wnon-virtual-dtor
|
||||
-Wsuggest-override
|
||||
|
||||
# We use 'ABCD' multichar for SaveLoad chunks identifiers
|
||||
-Wno-multichar
|
||||
|
||||
# Prevent optimisation supposing enums are in a range specified by the standard
|
||||
# For details, see http://gcc.gnu.org/PR43680 and PR#5246.
|
||||
-fno-strict-enums
|
||||
@@ -126,18 +118,6 @@ macro(compile_flags)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
|
||||
add_compile_options(
|
||||
-Wall
|
||||
# warning #873: function ... ::operator new ... has no corresponding operator delete ...
|
||||
-wd873
|
||||
# warning #1292: unknown attribute "fallthrough"
|
||||
-wd1292
|
||||
# warning #1899: multicharacter character literal (potential portability problem)
|
||||
-wd1899
|
||||
# warning #2160: anonymous union qualifier is ignored
|
||||
-wd2160
|
||||
)
|
||||
else()
|
||||
message(FATAL_ERROR "No warning flags are set for this compiler yet; please consider creating a Pull Request to add support for this compiler.")
|
||||
endif()
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
find_library(Soxr_LIBRARY
|
||||
NAMES soxr
|
||||
)
|
||||
|
||||
include(FixVcpkgLibrary)
|
||||
FixVcpkgLibrary(Soxr)
|
||||
|
||||
set(Soxr_COMPILE_OPTIONS "" CACHE STRING "Extra compile options of soxr")
|
||||
|
||||
set(Soxr_LINK_LIBRARIES "" CACHE STRING "Extra link libraries of soxr")
|
||||
|
||||
set(Soxr_LINK_FLAGS "" CACHE STRING "Extra link flags of soxr")
|
||||
|
||||
find_path(Soxr_INCLUDE_PATH
|
||||
NAMES soxr.h
|
||||
)
|
||||
|
||||
find_package_handle_standard_args(Soxr
|
||||
REQUIRED_VARS Soxr_LIBRARY Soxr_INCLUDE_PATH
|
||||
)
|
||||
|
||||
if(Soxr_FOUND)
|
||||
if(NOT TARGET Soxr::soxr)
|
||||
add_library(Soxr::soxr UNKNOWN IMPORTED)
|
||||
set_target_properties(Soxr::soxr PROPERTIES
|
||||
IMPORTED_LOCATION "${Soxr_LIBRARY}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${Soxr_INCLUDE_PATH}"
|
||||
INTERFACE_COMPILE_OPTIONS "${Soxr_COMPILE_OPTIONS}"
|
||||
INTERFACE_LINK_LIBRARIES "${Soxr_LINK_LIBRARIES}"
|
||||
INTERFACE_LINK_FLAGS "${Soxr_LINK_FLAGS}"
|
||||
)
|
||||
FixVcpkgTarget(Soxr Soxr::soxr)
|
||||
|
||||
# Prevent undefined references in UCRT64 MinGW environment
|
||||
if(MINGW AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
set_property(TARGET Soxr::soxr APPEND PROPERTY INTERFACE_LINK_LIBRARIES gomp)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
@@ -191,17 +191,26 @@ elseif(UNIX)
|
||||
set(PLATFORM "unknown")
|
||||
else()
|
||||
if(EXISTS "/etc/os-release")
|
||||
file(STRINGS "/etc/os-release" OS_RELEASE_CONTENTS REGEX "^ID=")
|
||||
string(REGEX MATCH "ID=(.*)" _ ${OS_RELEASE_CONTENTS})
|
||||
set(DISTRO_ID ${CMAKE_MATCH_1})
|
||||
if(DISTRO_ID STREQUAL "arch")
|
||||
file(STRINGS "/etc/os-release" OS_RELEASE_LIKE_CONTENTS REGEX "^ID_LIKE=")
|
||||
if (OS_RELEASE_LIKE_CONTENTS)
|
||||
string(REGEX MATCH "ID_LIKE=\\\"?([^\\\"]+)" _ ${OS_RELEASE_LIKE_CONTENTS})
|
||||
string(REGEX MATCHALL "([^ ]+)" DISTRO_LIKE_IDS ${CMAKE_MATCH_1})
|
||||
endif()
|
||||
if (DISTRO_LIKE_IDS)
|
||||
set(DISTRO_IDS ${DISTRO_LIKE_IDS})
|
||||
else()
|
||||
file(STRINGS "/etc/os-release" OS_RELEASE_CONTENTS REGEX "^ID=")
|
||||
string(REGEX MATCH "ID=(.*)" _ ${OS_RELEASE_CONTENTS})
|
||||
set(DISTRO_IDS ${CMAKE_MATCH_1})
|
||||
endif()
|
||||
if("arch" IN_LIST DISTRO_IDS)
|
||||
set(PLATFORM "arch")
|
||||
set(CPACK_GENERATOR "TXZ")
|
||||
elseif(DISTRO_ID STREQUAL "fedora" OR DISTRO_ID STREQUAL "rhel")
|
||||
elseif("fedora" IN_LIST DISTRO_IDS OR "rhel" IN_LIST DISTRO_IDS)
|
||||
set(PLATFORM "fedora")
|
||||
set(CPACK_GENERATOR "RPM")
|
||||
include(PackageRPM)
|
||||
elseif(DISTRO_ID STREQUAL "ubuntu" OR DISTRO_ID STREQUAL "debian" OR DISTRO_ID STREQUAL "linuxmint")
|
||||
elseif("debian" IN_LIST DISTRO_IDS OR "ubuntu" IN_LIST DISTRO_IDS OR "linuxmint" IN_LIST DISTRO_IDS)
|
||||
file(STRINGS "/etc/os-release" OS_RELEASE_CODENAME REGEX "^VERSION_CODENAME=")
|
||||
string(REGEX MATCH "VERSION_CODENAME=(.*)" _ ${OS_RELEASE_CODENAME})
|
||||
set(RELEASE_CODENAME ${CMAKE_MATCH_1})
|
||||
|
||||
+1
-1
@@ -726,7 +726,7 @@
|
||||
</ul>
|
||||
</li>
|
||||
<li>m3 bit 6 : free</li>
|
||||
<li>m3 bit 5 : The house is protected from the town upgrading it</li>
|
||||
<li>m3 bit 5 : The house is protected by the player from the town upgrading it</li>
|
||||
<li>m3 bits 4..0 : triggers activated <a href="#newhouses">(newhouses)</a></li>
|
||||
<li>m4 : free</li>
|
||||
<li>m5 : see m3 bit 7</li>
|
||||
|
||||
@@ -156,7 +156,7 @@ the array so you can quickly see what is used and what is not.
|
||||
<td class="caption">finished house</td>
|
||||
<td class="bits" rowspan=2><span class="used" title="House random bits">XXXX XXXX</span></td>
|
||||
<td class="bits" rowspan=2><span class="pool" title="Town index on pool">XXXX XXXX XXXX XXXX</span></td>
|
||||
<td class="bits"><span class="used" title="House is complete/in construction (see m5)">1</span><span class="free">O</span><span class="used" title="The house is protected from the town upgrading it.">X</span><span class="usable" title="Activated triggers (bits 2..4 don't have a meaning)">X XX</span><span class="used" title="Activated triggers (bits 2..4 don't have a meaning)">XX</span></td>
|
||||
<td class="bits"><span class="used" title="House is complete/in construction (see m5)">1</span><span class="free">O</span><span class="used" title="The house is protected by the player from the town upgrading it.">X</span><span class="usable" title="Activated triggers (bits 2..4 don't have a meaning)">X XX</span><span class="used" title="Activated triggers (bits 2..4 don't have a meaning)">XX</span></td>
|
||||
<td class="bits" rowspan=2><span class="free">OOOO OOOO</span></td>
|
||||
<td class="bits"><span class="used" title="Age in years, clamped at 255">XXXX XXXX</span></td>
|
||||
<td class="bits" rowspan=2><span class="abuse" title="Newhouses activated: periodic processing time remaining; if not, lift position for houses 04 and 05">XXXX XX</span><span class="used" title="Animated tile state">XX</span></td>
|
||||
@@ -165,7 +165,7 @@ the array so you can quickly see what is used and what is not.
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="caption">house under construction</td>
|
||||
<td class="bits"><span class="used" title="House is complete/in construction (see m5)">O</span><span class="free">O</span><span class="used" title="The house is protected from the town upgrading it.">X</span><span class="usable" title="Activated triggers (bits 2..4 don't have a meaning)">X XX</span><span class="used" title="Activated triggers (bits 2..4 don't have a meaning)">XX</span></td>
|
||||
<td class="bits"><span class="used" title="House is complete/in construction (see m5)">O</span><span class="free">O</span><span class="used" title="The house is protected by the player from the town upgrading it.">X</span><span class="usable" title="Activated triggers (bits 2..4 don't have a meaning)">X XX</span><span class="used" title="Activated triggers (bits 2..4 don't have a meaning)">XX</span></td>
|
||||
<td class="bits"><span class="free">OOO</span><span class="used" title="Construction stage">X X</span><span class="used" title="Construction counter">XXX</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
+16
-16
@@ -69,19 +69,19 @@ An example of a valid tag is `PLYR` when looking at it via ASCII, which contains
|
||||
`[4..4]` - Next follows a byte where the lower 4 bits contain the type.
|
||||
The possible valid types are:
|
||||
|
||||
- `0` - `CH_RIFF` - This chunk is a binary blob.
|
||||
- `1` - `CH_ARRAY` - This chunk is a list of items.
|
||||
- `2` - `CH_SPARSE_ARRAY` - This chunk is a list of items.
|
||||
- `3` - `CH_TABLE` - This chunk is self-describing list of items.
|
||||
- `4` - `CH_SPARSE_TABLE` - This chunk is self-describing list of items.
|
||||
- `0` - `ChunkType::Riff` - This chunk is a binary blob.
|
||||
- `1` - `ChunkType::Array` - This chunk is a list of items.
|
||||
- `2` - `ChunkType::SparseArray` - This chunk is a list of items.
|
||||
- `3` - `ChunkType::Table` - This chunk is self-describing list of items.
|
||||
- `4` - `ChunkType::SparseTable` - This chunk is self-describing list of items.
|
||||
|
||||
Now per type the format is (slightly) different.
|
||||
|
||||
### CH_RIFF
|
||||
### ChunkType::Riff
|
||||
|
||||
(since savegame version 295, this chunk type is only used for MAP-chunks, containing bit-information about each tile on the map)
|
||||
|
||||
A `CH_RIFF` starts with an `uint24` which together with the upper-bits of the type defines the length of the chunk.
|
||||
A `ChunkType::Riff` starts with an `uint24` which together with the upper-bits of the type defines the length of the chunk.
|
||||
In pseudo-code:
|
||||
|
||||
```
|
||||
@@ -94,11 +94,11 @@ if type == 0
|
||||
The next `length` bytes are part of the chunk.
|
||||
What those bytes mean depends on the tag of the chunk; further details per chunk can be found in the source-code.
|
||||
|
||||
### CH_ARRAY / CH_SPARSE_ARRAY
|
||||
### ChunkType::Array / ChunkType::SparseArray
|
||||
|
||||
(this chunk type is deprecated since savegame version 295 and is no longer in use)
|
||||
|
||||
`[0..G1]` - A `CH_ARRAY` / `CH_SPARSE_ARRAY` starts with a `gamma`, indicating the size of the next item plus one.
|
||||
`[0..G1]` - A `ChunkType::Array` / `ChunkType::SparseArray` starts with a `gamma`, indicating the size of the next item plus one.
|
||||
If this size value is zero, it indicates the end of the list.
|
||||
This indicates the full length of the next item minus one.
|
||||
In psuedo-code:
|
||||
@@ -111,21 +111,21 @@ loop
|
||||
read <size> bytes
|
||||
```
|
||||
|
||||
`[]` - For `CH_ARRAY` there is an implicit index.
|
||||
`[]` - For `ChunkType::Array` there is an implicit index.
|
||||
The loop starts at zero, and every iteration adds one to the index.
|
||||
For entries in the game that were not allocated, the `size` will be zero.
|
||||
|
||||
`[G1+1..G2]` - For `CH_SPARSE_ARRAY` there is an explicit index.
|
||||
`[G1+1..G2]` - For `ChunkType::SparseArray` there is an explicit index.
|
||||
The `gamma` following the size indicates the index.
|
||||
|
||||
The content of the item is a binary blob, and similar to `CH_RIFF`, it depends on the tag of the chunk what it means.
|
||||
The content of the item is a binary blob, and similar to `ChunkType::Riff`, it depends on the tag of the chunk what it means.
|
||||
Please check the source-code for further details.
|
||||
|
||||
### CH_TABLE / CH_SPARSE_TABLE
|
||||
### ChunkType::Table / ChunkType::SparseTable
|
||||
|
||||
(this chunk type only exists since savegame version 295)
|
||||
|
||||
Both `CH_TABLE` and `CH_SPARSE_TABLE` are very similar to `CH_ARRAY` / `CH_SPARSE_ARRAY` respectively.
|
||||
Both `ChunkType::Table` and `ChunkType::SparseTable` are very similar to `ChunkType::Array` / `ChunkType::SparseArray` respectively.
|
||||
The only change is that the chunk starts with a header.
|
||||
This header describes the chunk in details; with the header you know the meaning of each byte in the binary blob that follows.
|
||||
|
||||
@@ -168,7 +168,7 @@ struct | substruct3
|
||||
The headers will be, in order: `table`, `substruct1`, `substruct3`, `substruct2`, each ending with a `type` is zero field.
|
||||
|
||||
After reading all the fields of all the headers, there is a list of records.
|
||||
To read this, see `CH_ARRAY` / `CH_SPARSE_ARRAY` for details.
|
||||
To read this, see `ChunkType::Array` / `ChunkType::SparseArray` for details.
|
||||
|
||||
As each `type` has a well defined length, you can read the records even without knowing anything about the chunk-tag yourself.
|
||||
|
||||
@@ -187,7 +187,7 @@ The prefix is strongly advised to avoid conflicts with future-settings in an unp
|
||||
|
||||
## Scripts custom data format
|
||||
|
||||
Script chunks (`AIPL` and `GSDT`) use `CH_TABLE` chunk type.
|
||||
Script chunks (`AIPL` and `GSDT`) use `ChunkType::Table` chunk type.
|
||||
|
||||
At the end of each record there's an `uint8` to indicate if there's custom data (1) or not (0).
|
||||
|
||||
|
||||
Binary file not shown.
@@ -1 +1 @@
|
||||
c56aad31380c077d619e124bd87c8270
|
||||
b198439be549299b877e97ca3b58aef1
|
||||
|
||||
@@ -51,6 +51,9 @@ if(GRFCODEC_FOUND)
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/overlay_snowy_rocks_2.png
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/overlay_snowy_rocks_3.png
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/overlay_snowy_rocks_4.png
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/overlay_coastal_rocks.png
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/overlay_toyland_rocks.png
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/overlay_toyland_coastal_rocks.png
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/roadstops.png
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/road_waypoints.png
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/signals.png
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
@@ -4,7 +4,8 @@
|
||||
// See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
|
||||
//
|
||||
-1 * 0 0C "Overlay rocks"
|
||||
-1 * 3 05 1A 5F
|
||||
-1 * 0 07 83 01 \7= 03 73
|
||||
-1 * 3 05 1A 72
|
||||
|
||||
// Plain overlay rocks (unused...)
|
||||
-1 sprites/overlay_rocks.png 8bpp 1 1 64 31 -31 0 normal
|
||||
@@ -110,3 +111,71 @@
|
||||
-1 sprites/overlay_snowy_rocks_4.png 8bpp 1281 1 64 15 -31 0 normal
|
||||
-1 sprites/overlay_snowy_rocks_4.png 8bpp 1361 1 64 31 -31 -8 normal
|
||||
-1 sprites/overlay_snowy_rocks_4.png 8bpp 1441 1 64 31 -31 -8 normal
|
||||
|
||||
// Coastal rocks
|
||||
-1 sprites/overlay_coastal_rocks.png 8bpp 1 1 64 31 -31 0 normal
|
||||
-1 sprites/overlay_coastal_rocks.png 8bpp 81 1 64 31 -31 0 normal
|
||||
-1 sprites/overlay_coastal_rocks.png 8bpp 161 1 64 23 -31 0 normal
|
||||
-1 sprites/overlay_coastal_rocks.png 8bpp 241 1 64 23 -31 0 normal
|
||||
-1 sprites/overlay_coastal_rocks.png 8bpp 321 1 64 31 -31 0 normal
|
||||
-1 sprites/overlay_coastal_rocks.png 8bpp 401 1 64 31 -31 0 normal
|
||||
-1 sprites/overlay_coastal_rocks.png 8bpp 481 1 64 23 -31 0 normal
|
||||
-1 sprites/overlay_coastal_rocks.png 8bpp 561 1 64 23 -31 0 normal
|
||||
-1 sprites/overlay_coastal_rocks.png 8bpp 641 1 64 39 -31 -8 normal
|
||||
-1 sprites/overlay_coastal_rocks.png 8bpp 721 1 64 39 -31 -8 normal
|
||||
-1 sprites/overlay_coastal_rocks.png 8bpp 801 1 64 31 -31 -8 normal
|
||||
-1 sprites/overlay_coastal_rocks.png 8bpp 881 1 64 31 -31 -8 normal
|
||||
-1 sprites/overlay_coastal_rocks.png 8bpp 961 1 64 39 -31 -8 normal
|
||||
-1 sprites/overlay_coastal_rocks.png 8bpp 1041 1 64 39 -31 -8 normal
|
||||
-1 sprites/overlay_coastal_rocks.png 8bpp 1121 1 64 31 -31 -8 normal
|
||||
-1 sprites/overlay_coastal_rocks.png 8bpp 1201 1 64 47 -31 -16 normal
|
||||
-1 sprites/overlay_coastal_rocks.png 8bpp 1281 1 64 15 -31 0 normal
|
||||
-1 sprites/overlay_coastal_rocks.png 8bpp 1361 1 64 31 -31 -8 normal
|
||||
-1 sprites/overlay_coastal_rocks.png 8bpp 1441 1 64 31 -31 -8 normal
|
||||
|
||||
-1 * 6 07 83 01 \7! 03 28
|
||||
-1 * 3 05 1A 13
|
||||
|
||||
// Toyland rocks
|
||||
-1 sprites/overlay_toyland_rocks.png 8bpp 1 1 64 31 -31 0 normal
|
||||
-1 sprites/overlay_toyland_rocks.png 8bpp 81 1 64 31 -31 0 normal
|
||||
-1 sprites/overlay_toyland_rocks.png 8bpp 161 1 64 23 -31 0 normal
|
||||
-1 sprites/overlay_toyland_rocks.png 8bpp 241 1 64 23 -31 0 normal
|
||||
-1 sprites/overlay_toyland_rocks.png 8bpp 321 1 64 31 -31 0 normal
|
||||
-1 sprites/overlay_toyland_rocks.png 8bpp 401 1 64 31 -31 0 normal
|
||||
-1 sprites/overlay_toyland_rocks.png 8bpp 481 1 64 23 -31 0 normal
|
||||
-1 sprites/overlay_toyland_rocks.png 8bpp 561 1 64 23 -31 0 normal
|
||||
-1 sprites/overlay_toyland_rocks.png 8bpp 641 1 64 39 -31 -8 normal
|
||||
-1 sprites/overlay_toyland_rocks.png 8bpp 721 1 64 39 -31 -8 normal
|
||||
-1 sprites/overlay_toyland_rocks.png 8bpp 801 1 64 31 -31 -8 normal
|
||||
-1 sprites/overlay_toyland_rocks.png 8bpp 881 1 64 31 -31 -8 normal
|
||||
-1 sprites/overlay_toyland_rocks.png 8bpp 961 1 64 39 -31 -8 normal
|
||||
-1 sprites/overlay_toyland_rocks.png 8bpp 1041 1 64 39 -31 -8 normal
|
||||
-1 sprites/overlay_toyland_rocks.png 8bpp 1121 1 64 31 -31 -8 normal
|
||||
-1 sprites/overlay_toyland_rocks.png 8bpp 1201 1 64 47 -31 -16 normal
|
||||
-1 sprites/overlay_toyland_rocks.png 8bpp 1281 1 64 15 -31 0 normal
|
||||
-1 sprites/overlay_toyland_rocks.png 8bpp 1361 1 64 31 -31 -8 normal
|
||||
-1 sprites/overlay_toyland_rocks.png 8bpp 1441 1 64 31 -31 -8 normal
|
||||
|
||||
-1 * 3 05 9A 13 5F
|
||||
|
||||
// Toyland coastal rocks
|
||||
-1 sprites/overlay_toyland_coastal_rocks.png 8bpp 1 1 64 31 -31 0 normal
|
||||
-1 sprites/overlay_toyland_coastal_rocks.png 8bpp 81 1 64 31 -31 0 normal
|
||||
-1 sprites/overlay_toyland_coastal_rocks.png 8bpp 161 1 64 23 -31 0 normal
|
||||
-1 sprites/overlay_toyland_coastal_rocks.png 8bpp 241 1 64 23 -31 0 normal
|
||||
-1 sprites/overlay_toyland_coastal_rocks.png 8bpp 321 1 64 31 -31 0 normal
|
||||
-1 sprites/overlay_toyland_coastal_rocks.png 8bpp 401 1 64 31 -31 0 normal
|
||||
-1 sprites/overlay_toyland_coastal_rocks.png 8bpp 481 1 64 23 -31 0 normal
|
||||
-1 sprites/overlay_toyland_coastal_rocks.png 8bpp 561 1 64 23 -31 0 normal
|
||||
-1 sprites/overlay_toyland_coastal_rocks.png 8bpp 641 1 64 39 -31 -8 normal
|
||||
-1 sprites/overlay_toyland_coastal_rocks.png 8bpp 721 1 64 39 -31 -8 normal
|
||||
-1 sprites/overlay_toyland_coastal_rocks.png 8bpp 801 1 64 31 -31 -8 normal
|
||||
-1 sprites/overlay_toyland_coastal_rocks.png 8bpp 881 1 64 31 -31 -8 normal
|
||||
-1 sprites/overlay_toyland_coastal_rocks.png 8bpp 961 1 64 39 -31 -8 normal
|
||||
-1 sprites/overlay_toyland_coastal_rocks.png 8bpp 1041 1 64 39 -31 -8 normal
|
||||
-1 sprites/overlay_toyland_coastal_rocks.png 8bpp 1121 1 64 31 -31 -8 normal
|
||||
-1 sprites/overlay_toyland_coastal_rocks.png 8bpp 1201 1 64 47 -31 -16 normal
|
||||
-1 sprites/overlay_toyland_coastal_rocks.png 8bpp 1281 1 64 15 -31 0 normal
|
||||
-1 sprites/overlay_toyland_coastal_rocks.png 8bpp 1361 1 64 31 -31 -8 normal
|
||||
-1 sprites/overlay_toyland_coastal_rocks.png 8bpp 1441 1 64 31 -31 -8 normal
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 8.9 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 6.7 KiB |
@@ -1,11 +1,8 @@
|
||||
# If you change this version, change the numbers in .github/workflows/ci-emscripten.yml (2x)
|
||||
# and .github/workflows/preview-build.yml (2x) too.
|
||||
FROM emscripten/emsdk:3.1.57
|
||||
FROM emscripten/emsdk:6.0.1
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y gcc-12 g++-12 \
|
||||
&& update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-12 100 \
|
||||
&& update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-12 100 \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
||||
@@ -227,7 +227,7 @@ function Regression::Airport()
|
||||
print(" GetAirportNumHelipads(" + i + "): " + AIAirport.GetAirportNumHelipads(i));
|
||||
}
|
||||
|
||||
print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF));
|
||||
local accounting = AIAccounting();
|
||||
print(" GetPrice(): " + AIAirport.GetPrice(0));
|
||||
print(" BuildAirport(): " + AIAirport.BuildAirport(32116, 0, AIStation.STATION_JOIN_ADJACENT));
|
||||
print(" IsHangarTile(): " + AIAirport.IsHangarTile(32116));
|
||||
@@ -237,12 +237,13 @@ function Regression::Airport()
|
||||
print(" IsHangarTile(): " + AIAirport.IsHangarTile(32119));
|
||||
print(" IsAirportTile(): " + AIAirport.IsAirportTile(32119));
|
||||
print(" GetAirportType(): " + AIAirport.GetAirportType(32119));
|
||||
print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF));
|
||||
print(" GetCosts(): " + accounting.GetCosts());
|
||||
|
||||
accounting.ResetCosts();
|
||||
print(" RemoveAirport(): " + AIAirport.RemoveAirport(32118));
|
||||
print(" IsHangarTile(): " + AIAirport.IsHangarTile(32119));
|
||||
print(" IsAirportTile(): " + AIAirport.IsAirportTile(32119));
|
||||
print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF));
|
||||
print(" GetCosts(): " + accounting.GetCosts());
|
||||
print(" BuildAirport(): " + AIAirport.BuildAirport(32116, 0, AIStation.STATION_JOIN_ADJACENT));
|
||||
}
|
||||
|
||||
@@ -1167,7 +1168,7 @@ function Regression::Marine()
|
||||
print(" IsLockTile(): " + AIMarine.IsLockTile(32116));
|
||||
print(" IsCanalTile(): " + AIMarine.IsCanalTile(32116));
|
||||
|
||||
print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF));
|
||||
local accounting = AIAccounting();
|
||||
print(" BuildWaterDepot(): " + AIMarine.BuildWaterDepot(28479, 28478));
|
||||
print(" BuildDock(): " + AIMarine.BuildDock(29253, AIStation.STATION_JOIN_ADJACENT));
|
||||
print(" BuildBuoy(): " + AIMarine.BuildBuoy(28481));
|
||||
@@ -1180,7 +1181,7 @@ function Regression::Marine()
|
||||
print(" IsBuoyTile(): " + AIMarine.IsBuoyTile(28481));
|
||||
print(" IsLockTile(): " + AIMarine.IsLockTile(28487));
|
||||
print(" IsCanalTile(): " + AIMarine.IsCanalTile(32127));
|
||||
print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF));
|
||||
print(" GetCosts(): " + accounting.GetCosts());
|
||||
|
||||
local list = AIWaypointList(AIWaypoint.WAYPOINT_BUOY);
|
||||
print("");
|
||||
@@ -1196,6 +1197,7 @@ function Regression::Marine()
|
||||
}
|
||||
print("");
|
||||
|
||||
accounting.ResetCosts();
|
||||
print(" RemoveWaterDepot(): " + AIMarine.RemoveWaterDepot(28479));
|
||||
print(" RemoveDock(): " + AIMarine.RemoveDock(29253));
|
||||
print(" RemoveBuoy(): " + AIMarine.RemoveBuoy(28481));
|
||||
@@ -1206,7 +1208,7 @@ function Regression::Marine()
|
||||
print(" IsBuoyTile(): " + AIMarine.IsBuoyTile(28481));
|
||||
print(" IsLockTile(): " + AIMarine.IsLockTile(28487));
|
||||
print(" IsCanalTile(): " + AIMarine.IsCanalTile(32127));
|
||||
print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF));
|
||||
print(" GetCosts(): " + accounting.GetCosts());
|
||||
|
||||
print(" BuildWaterDepot(): " + AIMarine.BuildWaterDepot(28479, 28480));
|
||||
print(" BuildDock(): " + AIMarine.BuildDock(29253, AIStation.STATION_JOIN_ADJACENT));
|
||||
@@ -1220,6 +1222,7 @@ function Regression::Order()
|
||||
print("");
|
||||
print("--Order--");
|
||||
print(" GetOrderCount(): " + AIOrder.GetOrderCount(12));
|
||||
print(" GetOrderCount(): " + AIOrder.GetOrderCount(9999));
|
||||
print(" GetOrderDestination(): " + AIOrder.GetOrderDestination(12, 1));
|
||||
print(" AreOrderFlagsValid(): " + AIOrder.AreOrderFlagsValid(33416, AIOrder.OF_TRANSFER));
|
||||
print(" AreOrderFlagsValid(): " + AIOrder.AreOrderFlagsValid(33416, AIOrder.OF_TRANSFER | AIOrder.OF_UNLOAD));
|
||||
@@ -1396,6 +1399,9 @@ function Regression::Rail()
|
||||
print(" Depot");
|
||||
print(" IsRailTile(): " + AIRail.IsRailTile(33411));
|
||||
print(" BuildRailDepot(): " + AIRail.BuildRailDepot(0, 1));
|
||||
print(" RemoveRailDepot(): " + AIRail.RemoveRailDepot(33411));
|
||||
print(" BuildRailDepot(): " + AIRail.BuildRailDepot(33411, 33412));
|
||||
print(" RemoveRailDepot(): " + AIRail.RemoveRailDepot(33411));
|
||||
print(" BuildRailDepot(): " + AIRail.BuildRailDepot(33411, 33411));
|
||||
print(" BuildRailDepot(): " + AIRail.BuildRailDepot(33411, 33410));
|
||||
print(" BuildRailDepot(): " + AIRail.BuildRailDepot(33411, 33414));
|
||||
@@ -2105,11 +2111,14 @@ function Regression::Vehicle()
|
||||
print(" GetWagonAge(): " + AIVehicle.GetWagonAge(17, 2));
|
||||
print(" GetWagonEngineType(): " + AIVehicle.GetWagonEngineType(17 3));
|
||||
print(" GetWagonAge(): " + AIVehicle.GetWagonAge(17, 3));
|
||||
print(" GetVehicleType(): " + AIVehicle.GetVehicleType(14));
|
||||
print(" GetLength(): " + AIVehicle.GetLength(14));
|
||||
|
||||
print(" --Refit--");
|
||||
print(" GetBuildWithRefitCapacity(): " + AIVehicle.GetBuildWithRefitCapacity(28479, 211, 255));
|
||||
print(" GetBuildWithRefitCapacity(): " + AIVehicle.GetBuildWithRefitCapacity(28479, 211, 0));
|
||||
print(" GetBuildWithRefitCapacity(): " + AIVehicle.GetBuildWithRefitCapacity(28479, 211, 9));
|
||||
print(" GetBuildWithRefitCapacity(): " + AIVehicle.GetBuildWithRefitCapacity(28481, 211, 0));
|
||||
print(" BuildVehicleWithRefit(): " + AIVehicle.BuildVehicleWithRefit(28479, 211, 9));
|
||||
print(" GetCapacity(): " + AIVehicle.GetCapacity(20, 9));
|
||||
print(" GetCapacity(): " + AIVehicle.GetCapacity(20, 5));
|
||||
@@ -2300,6 +2309,81 @@ function Regression::PriorityQueue()
|
||||
print(" Count(): " + queue.Count());
|
||||
}
|
||||
|
||||
function Regression::Terraforming()
|
||||
{
|
||||
local accounting = AIAccounting();
|
||||
print("");
|
||||
print("--Terraforming--");
|
||||
print(" DemolishTile(): " + AITile.DemolishTile(4033));
|
||||
print(" DemolishTile(): " + AITile.DemolishTile(60766));
|
||||
print(" GetCosts(): " + accounting.GetCosts());
|
||||
accounting.ResetCosts();
|
||||
print(" LowerTile(): " + AITile.LowerTile(8205, AITile.SLOPE_ENW));
|
||||
print(" RaiseTile(): " + AITile.RaiseTile(8205, AITile.SLOPE_ENW));
|
||||
print(" GetCosts(): " + accounting.GetCosts());
|
||||
accounting.ResetCosts();
|
||||
print(" LowerTile(): " + AITile.LowerTile(8205, AITile.SLOPE_ENW));
|
||||
print(" GetCosts(): " + accounting.GetCosts());
|
||||
accounting.ResetCosts();
|
||||
print(" LowerTile(): " + AITile.LowerTile(4113, AITile.SLOPE_SW));
|
||||
print(" RaiseTile(): " + AITile.RaiseTile(5902, AITile.SLOPE_NE));
|
||||
print(" GetCosts(): " + accounting.GetCosts());
|
||||
accounting.ResetCosts();
|
||||
print(" RaiseTile(): " + AITile.RaiseTile(7958, AITile.SLOPE_SE));
|
||||
print(" LowerTile(): " + AITile.LowerTile(7958, AITile.SLOPE_NE));
|
||||
print(" LowerTile(): " + AITile.LowerTile(7958, AITile.SLOPE_SE));
|
||||
print(" RaiseTile(): " + AITile.RaiseTile(7958, AITile.SLOPE_SE));
|
||||
print(" LowerTile(): " + AITile.LowerTile(7958, AITile.SLOPE_EW));
|
||||
print(" GetCosts(): " + accounting.GetCosts());
|
||||
accounting.ResetCosts();
|
||||
print(" LowerTile(): " + AITile.LowerTile(33924, AITile.SLOPE_ELEVATED));
|
||||
print(" LowerTile(): " + AITile.LowerTile(33923, AITile.SLOPE_ELEVATED));
|
||||
print(" RaiseTile(): " + AITile.RaiseTile(34193, AITile.SLOPE_ELEVATED));
|
||||
print(" LowerTile(): " + AITile.LowerTile(34193, AITile.SLOPE_ELEVATED));
|
||||
print(" LowerTile(): " + AITile.LowerTile(34192, AITile.SLOPE_NE));
|
||||
print(" RaiseTile(): " + AITile.RaiseTile(34193, AITile.SLOPE_ELEVATED));
|
||||
print(" LowerTile(): " + AITile.LowerTile(34192, AITile.SLOPE_NE));
|
||||
print(" GetCosts(): " + accounting.GetCosts());
|
||||
accounting.ResetCosts();
|
||||
print(" RaiseTile(): " + AITile.RaiseTile(5687, AITile.SLOPE_N));
|
||||
print(" LowerTile(): " + AITile.LowerTile(5687, AITile.SLOPE_SE));
|
||||
print(" GetCosts(): " + accounting.GetCosts());
|
||||
accounting.ResetCosts();
|
||||
print(" RaiseTile(): " + AITile.RaiseTile(23596, AITile.SLOPE_NE));
|
||||
print(" LowerTile(): " + AITile.LowerTile(23596, AITile.SLOPE_NE));
|
||||
print(" GetCosts(): " + accounting.GetCosts());
|
||||
accounting.ResetCosts();
|
||||
print(" RaiseTile(): " + AITile.RaiseTile(28536, AITile.SLOPE_E));
|
||||
print(" RaiseTile(): " + AITile.RaiseTile(28536, AITile.SLOPE_E));
|
||||
print(" GetCosts(): " + accounting.GetCosts());
|
||||
accounting.ResetCosts();
|
||||
print(" LevelTiles(): " + AITile.LevelTiles(28536, 29053));
|
||||
print(" LevelTiles(): " + AITile.LevelTiles(28536, 29053));
|
||||
print(" GetCosts(): " + accounting.GetCosts());
|
||||
accounting.ResetCosts();
|
||||
print(" LevelTiles(): " + AITile.LevelTiles(22348, 24405));
|
||||
print(" LevelTiles(): " + AITile.LevelTiles(27717, 29772));
|
||||
print(" GetCosts(): " + accounting.GetCosts());
|
||||
accounting.ResetCosts();
|
||||
print(" LowerTile(): " + AITile.LowerTile(61534, AITile.SLOPE_W));
|
||||
print(" RaiseTile(): " + AITile.RaiseTile(61534, AITile.SLOPE_NE));
|
||||
print(" RaiseTile(): " + AITile.RaiseTile(61534, AITile.SLOPE_N));
|
||||
print(" LowerTile(): " + AITile.LowerTile(61534, AITile.SLOPE_W));
|
||||
print(" GetCosts(): " + accounting.GetCosts());
|
||||
accounting.ResetCosts();
|
||||
print(" RaiseTile(): " + AITile.RaiseTile(61534, AITile.SLOPE_N));
|
||||
print(" LowerTile(): " + AITile.LowerTile(61533, AITile.SLOPE_E));
|
||||
print(" LowerTile(): " + AITile.LowerTile(61534, AITile.SLOPE_E));
|
||||
print(" GetCosts(): " + accounting.GetCosts());
|
||||
accounting.ResetCosts();
|
||||
print(" RaiseTile(): " + AITile.RaiseTile(4033, AITile.SLOPE_S));
|
||||
print(" LowerTile(): " + AITile.LowerTile(4033, AITile.SLOPE_S));
|
||||
print(" LowerTile(): " + AITile.LowerTile(4033, AITile.SLOPE_E));
|
||||
print(" RaiseTile(): " + AITile.RaiseTile(4033, AITile.SLOPE_E));
|
||||
print(" RaiseTile(): " + AITile.RaiseTile(4033, AITile.SLOPE_NWS));
|
||||
print(" GetCosts(): " + accounting.GetCosts());
|
||||
}
|
||||
|
||||
function Regression::Start()
|
||||
{
|
||||
this.TestInit();
|
||||
@@ -2398,6 +2482,7 @@ function Regression::Start()
|
||||
|
||||
this.Math();
|
||||
this.PriorityQueue();
|
||||
this.Terraforming();
|
||||
|
||||
/* Check Valuate() is actually limited, MUST BE THE LAST TEST. */
|
||||
print("--Valuate() with excessive CPU usage--")
|
||||
@@ -2411,4 +2496,3 @@ function Regression::Start()
|
||||
}
|
||||
list.Valuate(Infinite);
|
||||
}
|
||||
|
||||
|
||||
@@ -1643,7 +1643,6 @@ ERROR: IsEnd() is invalid as Begin() is never called
|
||||
GetAirportHeight(9): -1
|
||||
GetAirportCoverageRadius(9): -1
|
||||
GetAirportNumHelipads(9): -1
|
||||
GetBankBalance(): 1999999790
|
||||
GetPrice(): 5400
|
||||
BuildAirport(): true
|
||||
IsHangarTile(): false
|
||||
@@ -1653,11 +1652,11 @@ ERROR: IsEnd() is invalid as Begin() is never called
|
||||
IsHangarTile(): true
|
||||
IsAirportTile(): true
|
||||
GetAirportType(): 0
|
||||
GetBankBalance(): 1999989890
|
||||
GetCosts(): 9900
|
||||
RemoveAirport(): true
|
||||
IsHangarTile(): false
|
||||
IsAirportTile(): false
|
||||
GetBankBalance(): 1999989626
|
||||
GetCosts(): 264
|
||||
BuildAirport(): true
|
||||
|
||||
--Bridge--
|
||||
@@ -8413,7 +8412,6 @@ ERROR: IsEnd() is invalid as Begin() is never called
|
||||
IsBuoyTile(): false
|
||||
IsLockTile(): false
|
||||
IsCanalTile(): false
|
||||
GetBankBalance(): 1999979304
|
||||
BuildWaterDepot(): true
|
||||
BuildDock(): true
|
||||
BuildBuoy(): true
|
||||
@@ -8426,7 +8424,7 @@ ERROR: IsEnd() is invalid as Begin() is never called
|
||||
IsBuoyTile(): true
|
||||
IsLockTile(): true
|
||||
IsCanalTile(): true
|
||||
GetBankBalance(): 1999964680
|
||||
GetCosts(): 14624
|
||||
|
||||
--AIWaypointList(BUOY)--
|
||||
Count(): 1
|
||||
@@ -8445,7 +8443,7 @@ ERROR: IsEnd() is invalid as Begin() is never called
|
||||
IsBuoyTile(): false
|
||||
IsLockTile(): false
|
||||
IsCanalTile(): false
|
||||
GetBankBalance(): 1999959285
|
||||
GetCosts(): 5395
|
||||
BuildWaterDepot(): true
|
||||
BuildDock(): true
|
||||
BuildBuoy(): true
|
||||
@@ -8556,6 +8554,9 @@ ERROR: IsEnd() is invalid as Begin() is never called
|
||||
Depot
|
||||
IsRailTile(): false
|
||||
BuildRailDepot(): false
|
||||
RemoveRailDepot(): false
|
||||
BuildRailDepot(): true
|
||||
RemoveRailDepot(): true
|
||||
BuildRailDepot(): false
|
||||
BuildRailDepot(): true
|
||||
BuildRailDepot(): true
|
||||
@@ -10585,10 +10586,13 @@ ERROR: IsEnd() is invalid as Begin() is never called
|
||||
GetWagonAge(): 0
|
||||
GetWagonEngineType(): 65535
|
||||
GetWagonAge(): -1
|
||||
GetVehicleType(): 3
|
||||
GetLength(): -1
|
||||
--Refit--
|
||||
GetBuildWithRefitCapacity(): -1
|
||||
GetBuildWithRefitCapacity(): 0
|
||||
GetBuildWithRefitCapacity(): 160
|
||||
GetBuildWithRefitCapacity(): -1
|
||||
BuildVehicleWithRefit(): 20
|
||||
GetCapacity(): 160
|
||||
GetCapacity(): 0
|
||||
@@ -10628,11 +10632,11 @@ ERROR: IsEnd() is invalid as Begin() is never called
|
||||
14 => 1
|
||||
12 => 1
|
||||
Age ListDump:
|
||||
14 => 1
|
||||
13 => 1
|
||||
12 => 1
|
||||
17 => 0
|
||||
16 => 0
|
||||
14 => 0
|
||||
13 => 0
|
||||
12 => 0
|
||||
MaxAge ListDump:
|
||||
16 => 10980
|
||||
14 => 10980
|
||||
@@ -10641,10 +10645,10 @@ ERROR: IsEnd() is invalid as Begin() is never called
|
||||
12 => 5490
|
||||
AgeLeft ListDump:
|
||||
16 => 10980
|
||||
14 => 10980
|
||||
14 => 10979
|
||||
17 => 7320
|
||||
13 => 5490
|
||||
12 => 5490
|
||||
13 => 5489
|
||||
12 => 5489
|
||||
CurrentSpeed ListDump:
|
||||
12 => 27
|
||||
17 => 0
|
||||
@@ -10662,7 +10666,7 @@ ERROR: IsEnd() is invalid as Begin() is never called
|
||||
16 => 0
|
||||
14 => 0
|
||||
13 => 0
|
||||
12 => 0
|
||||
12 => -1
|
||||
ProfitLastYear ListDump:
|
||||
17 => 0
|
||||
16 => 0
|
||||
@@ -10702,6 +10706,7 @@ ERROR: IsEnd() is invalid as Begin() is never called
|
||||
|
||||
--Order--
|
||||
GetOrderCount(): 0
|
||||
GetOrderCount(): -1
|
||||
GetOrderDestination(): -1
|
||||
AreOrderFlagsValid(): true
|
||||
AreOrderFlagsValid(): false
|
||||
@@ -10872,6 +10877,63 @@ ERROR: IsEnd() is invalid as Begin() is never called
|
||||
Clear(): (null : 0x00000000)
|
||||
IsEmpty(): true
|
||||
Count(): 0
|
||||
|
||||
--Terraforming--
|
||||
DemolishTile(): true
|
||||
DemolishTile(): true
|
||||
GetCosts(): 120
|
||||
LowerTile(): false
|
||||
RaiseTile(): true
|
||||
GetCosts(): 60561
|
||||
LowerTile(): true
|
||||
GetCosts(): 561
|
||||
LowerTile(): true
|
||||
RaiseTile(): true
|
||||
GetCosts(): 30958
|
||||
RaiseTile(): false
|
||||
LowerTile(): false
|
||||
LowerTile(): true
|
||||
RaiseTile(): true
|
||||
LowerTile(): true
|
||||
GetCosts(): 3078
|
||||
LowerTile(): false
|
||||
LowerTile(): true
|
||||
RaiseTile(): false
|
||||
LowerTile(): true
|
||||
LowerTile(): false
|
||||
RaiseTile(): true
|
||||
LowerTile(): true
|
||||
GetCosts(): 5701
|
||||
RaiseTile(): true
|
||||
LowerTile(): true
|
||||
GetCosts(): 16055
|
||||
RaiseTile(): false
|
||||
LowerTile(): true
|
||||
GetCosts(): 2076
|
||||
RaiseTile(): true
|
||||
RaiseTile(): true
|
||||
GetCosts(): 10222
|
||||
LevelTiles(): true
|
||||
LevelTiles(): false
|
||||
GetCosts(): 9778
|
||||
LevelTiles(): true
|
||||
LevelTiles(): true
|
||||
GetCosts(): 288629
|
||||
LowerTile(): false
|
||||
RaiseTile(): true
|
||||
RaiseTile(): false
|
||||
LowerTile(): true
|
||||
GetCosts(): 6099
|
||||
RaiseTile(): true
|
||||
LowerTile(): true
|
||||
LowerTile(): false
|
||||
GetCosts(): 1317
|
||||
RaiseTile(): false
|
||||
LowerTile(): true
|
||||
LowerTile(): false
|
||||
RaiseTile(): false
|
||||
RaiseTile(): true
|
||||
GetCosts(): 38996
|
||||
--Valuate() with excessive CPU usage--
|
||||
constructor failed with: excessive CPU usage in list filter function
|
||||
Your script made an error: excessive CPU usage in valuator function
|
||||
@@ -10880,7 +10942,7 @@ CALLSTACK WITH LOCALS
|
||||
*FUNCTION [Valuate()] Valuate line [5]
|
||||
[args] ARRAY
|
||||
[this] INSTANCE
|
||||
*FUNCTION [Start()] regression/main.nut line [2412]
|
||||
*FUNCTION [Start()] regression/main.nut line [2497]
|
||||
[Infinite] CLOSURE
|
||||
[list] INSTANCE
|
||||
[this] INSTANCE
|
||||
|
||||
@@ -50,6 +50,11 @@ add_files(
|
||||
CONDITION OpusFile_FOUND
|
||||
)
|
||||
|
||||
add_files(
|
||||
soundresampler_soxr.cpp
|
||||
CONDITION Soxr_FOUND
|
||||
)
|
||||
|
||||
add_files(
|
||||
aircraft.h
|
||||
aircraft_cmd.cpp
|
||||
@@ -139,6 +144,7 @@ add_files(
|
||||
date_gui.h
|
||||
debug.cpp
|
||||
debug.h
|
||||
debug_type.h
|
||||
dedicated.cpp
|
||||
depot.cpp
|
||||
depot_base.h
|
||||
@@ -336,6 +342,7 @@ add_files(
|
||||
newgrf_town.h
|
||||
newgrf_townname.cpp
|
||||
newgrf_townname.h
|
||||
newgrf_type.h
|
||||
news_cmd.h
|
||||
news_func.h
|
||||
news_gui.cpp
|
||||
@@ -399,6 +406,8 @@ add_files(
|
||||
roadveh_cmd.h
|
||||
roadveh_gui.cpp
|
||||
safeguards.h
|
||||
screensaver.cpp
|
||||
screensaver.h
|
||||
screenshot_bmp.cpp
|
||||
screenshot_gui.cpp
|
||||
screenshot_gui.h
|
||||
@@ -450,6 +459,7 @@ add_files(
|
||||
soundloader_type.h
|
||||
soundloader_raw.cpp
|
||||
soundloader_wav.cpp
|
||||
soundresampler_type.h
|
||||
source_type.h
|
||||
sprite.cpp
|
||||
sprite.h
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
#ifndef AI_HPP
|
||||
#define AI_HPP
|
||||
|
||||
#include "../script/api/script_event_types.hpp"
|
||||
#include "../script/api/script_event.hpp"
|
||||
#include "ai_scanner.hpp"
|
||||
|
||||
/**
|
||||
|
||||
+15
-5
@@ -69,6 +69,16 @@
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the \c PerformanceElement for the AI of the given company.
|
||||
* @param company The company to get the PerformanceElement for.
|
||||
* @return The \c PerformanceElement.
|
||||
*/
|
||||
static constexpr PerformanceElement GetAIPerformanceElement(CompanyID company)
|
||||
{
|
||||
return static_cast<PerformanceElement>(PerformanceElement::AI0 + company);
|
||||
}
|
||||
|
||||
/* static */ void AI::GameLoop()
|
||||
{
|
||||
/* If we are in networking, only servers run this function, and that only if it is allowed */
|
||||
@@ -81,7 +91,7 @@
|
||||
|
||||
for (const Company *c : Company::Iterate()) {
|
||||
if (c->is_ai) {
|
||||
PerformanceMeasurer framerate((PerformanceElement)(PFE_AI0 + c->index));
|
||||
PerformanceMeasurer framerate(GetAIPerformanceElement(c->index));
|
||||
AutoRestoreBackup cur_company(_current_company, c->index);
|
||||
c->ai_instance->GameLoop();
|
||||
/* Occasionally collect garbage; every 255 ticks do one company.
|
||||
@@ -90,7 +100,7 @@
|
||||
c->ai_instance->CollectGarbage();
|
||||
}
|
||||
} else {
|
||||
PerformanceMeasurer::SetInactive((PerformanceElement)(PFE_AI0 + c->index));
|
||||
PerformanceMeasurer::SetInactive(GetAIPerformanceElement(c->index));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -103,7 +113,7 @@
|
||||
/* static */ void AI::Stop(CompanyID company)
|
||||
{
|
||||
if (_networking && !_network_server) return;
|
||||
PerformanceMeasurer::SetInactive((PerformanceElement)(PFE_AI0 + company));
|
||||
PerformanceMeasurer::SetInactive(GetAIPerformanceElement(company));
|
||||
|
||||
AutoRestoreBackup cur_company(_current_company, company);
|
||||
Company *c = Company::Get(company);
|
||||
@@ -189,14 +199,14 @@
|
||||
for (CompanyID c = CompanyID::Begin(); c < MAX_COMPANIES; ++c) {
|
||||
if (_settings_game.script_config.ai[c] != nullptr && _settings_game.script_config.ai[c]->HasScript()) {
|
||||
if (!_settings_game.script_config.ai[c]->ResetInfo(true)) {
|
||||
Debug(script, 0, "After a reload, the AI by the name '{}' was no longer found, and removed from the list.", _settings_game.script_config.ai[c]->GetName());
|
||||
Debug(Facility::Script, Severity::Critical, "After a reload, the AI by the name '{}' was no longer found, and removed from the list.", _settings_game.script_config.ai[c]->GetName());
|
||||
_settings_game.script_config.ai[c]->Change(std::nullopt);
|
||||
}
|
||||
}
|
||||
|
||||
if (_settings_newgame.script_config.ai[c] != nullptr && _settings_newgame.script_config.ai[c]->HasScript()) {
|
||||
if (!_settings_newgame.script_config.ai[c]->ResetInfo(false)) {
|
||||
Debug(script, 0, "After a reload, the AI by the name '{}' was no longer found, and removed from the list.", _settings_newgame.script_config.ai[c]->GetName());
|
||||
Debug(Facility::Script, Severity::Critical, "After a reload, the AI by the name '{}' was no longer found, and removed from the list.", _settings_newgame.script_config.ai[c]->GetName());
|
||||
_settings_newgame.script_config.ai[c]->Change(std::nullopt);
|
||||
}
|
||||
}
|
||||
|
||||
+7
-5
@@ -22,6 +22,8 @@
|
||||
#include "ai_info.hpp"
|
||||
#include "../script/script_gui.h"
|
||||
|
||||
#include "../widgets/ai_widget.h"
|
||||
|
||||
#include "table/strings.h"
|
||||
|
||||
#include "../safeguards.h"
|
||||
@@ -70,11 +72,11 @@ static constexpr std::initializer_list<NWidgetPart> _nested_ai_config_widgets =
|
||||
NWidget(NWID_VERTICAL, NWidContainerFlag::EqualSize),
|
||||
NWidget(NWID_HORIZONTAL, NWidContainerFlag::EqualSize),
|
||||
NWidget(WWT_PUSHTXTBTN, Colours::Yellow, WID_AIC_OPEN_URL), SetResize(1, 0), SetFill(1, 0), SetStringTip(STR_CONTENT_OPEN_URL, STR_CONTENT_OPEN_URL_TOOLTIP),
|
||||
NWidget(WWT_PUSHTXTBTN, Colours::Yellow, WID_AIC_TEXTFILE + TFT_README), SetFill(1, 1), SetResize(1, 0), SetStringTip(STR_TEXTFILE_VIEW_README, STR_TEXTFILE_VIEW_README_TOOLTIP),
|
||||
NWidget(WWT_PUSHTXTBTN, Colours::Yellow, WID_AIC_TEXTFILE + TextfileType::Readme), SetFill(1, 1), SetResize(1, 0), SetStringTip(STR_TEXTFILE_VIEW_README, STR_TEXTFILE_VIEW_README_TOOLTIP),
|
||||
EndContainer(),
|
||||
NWidget(NWID_HORIZONTAL, NWidContainerFlag::EqualSize),
|
||||
NWidget(WWT_PUSHTXTBTN, Colours::Yellow, WID_AIC_TEXTFILE + TFT_CHANGELOG), SetFill(1, 1), SetResize(1, 0), SetStringTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_TEXTFILE_VIEW_CHANGELOG_TOOLTIP),
|
||||
NWidget(WWT_PUSHTXTBTN, Colours::Yellow, WID_AIC_TEXTFILE + TFT_LICENSE), SetFill(1, 1), SetResize(1, 0), SetStringTip(STR_TEXTFILE_VIEW_LICENCE, STR_TEXTFILE_VIEW_LICENCE_TOOLTIP),
|
||||
NWidget(WWT_PUSHTXTBTN, Colours::Yellow, WID_AIC_TEXTFILE + TextfileType::Changelog), SetFill(1, 1), SetResize(1, 0), SetStringTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_TEXTFILE_VIEW_CHANGELOG_TOOLTIP),
|
||||
NWidget(WWT_PUSHTXTBTN, Colours::Yellow, WID_AIC_TEXTFILE + TextfileType::License), SetFill(1, 1), SetResize(1, 0), SetStringTip(STR_TEXTFILE_VIEW_LICENCE, STR_TEXTFILE_VIEW_LICENCE_TOOLTIP),
|
||||
EndContainer(),
|
||||
EndContainer(),
|
||||
EndContainer(),
|
||||
@@ -215,7 +217,7 @@ struct AIConfigWindow : public Window {
|
||||
|
||||
void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
|
||||
{
|
||||
if (widget >= WID_AIC_TEXTFILE && widget < WID_AIC_TEXTFILE + TFT_CONTENT_END) {
|
||||
if (widget >= WID_AIC_TEXTFILE && widget < WID_AIC_TEXTFILE + TextfileType::ContentEnd) {
|
||||
if (this->selected_slot == CompanyID::Invalid() || AIConfig::GetConfig(this->selected_slot) == nullptr) return;
|
||||
|
||||
ShowScriptTextfileWindow(this, static_cast<TextfileType>(widget - WID_AIC_TEXTFILE), this->selected_slot);
|
||||
@@ -326,7 +328,7 @@ struct AIConfigWindow : public Window {
|
||||
this->SetWidgetDisabledState(WID_AIC_MOVE_DOWN, !IsEditable(this->selected_slot) || !IsEditable(static_cast<CompanyID>(this->selected_slot + 1)));
|
||||
|
||||
this->SetWidgetDisabledState(WID_AIC_OPEN_URL, this->selected_slot == CompanyID::Invalid() || config->GetInfo() == nullptr || config->GetInfo()->GetURL().empty());
|
||||
for (TextfileType tft : EnumRange(TFT_CONTENT_BEGIN, TFT_CONTENT_END)) {
|
||||
for (TextfileType tft : EnumRange(TextfileType::ContentBegin, TextfileType::ContentEnd)) {
|
||||
this->SetWidgetDisabledState(WID_AIC_TEXTFILE + tft, this->selected_slot == CompanyID::Invalid() || !config->GetTextfile(tft, this->selected_slot).has_value());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ void AIScannerInfo::RegisterAPI(class Squirrel &engine)
|
||||
AIInfo *AIScannerInfo::SelectRandomAI() const
|
||||
{
|
||||
if (_game_mode == GameMode::Menu) {
|
||||
Debug(script, 0, "The intro game should not use AI, loading 'dummy' AI.");
|
||||
Debug(Facility::Script, Severity::Critical, "The intro game should not use AI, loading 'dummy' AI.");
|
||||
return this->info_dummy.get();
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ AIInfo *AIScannerInfo::SelectRandomAI() const
|
||||
|
||||
uint num_random_ais = std::ranges::distance(random_ais);
|
||||
if (num_random_ais == 0) {
|
||||
Debug(script, 0, "No suitable AI found, loading 'dummy' AI.");
|
||||
Debug(Facility::Script, Severity::Critical, "No suitable AI found, loading 'dummy' AI.");
|
||||
return this->info_dummy.get();
|
||||
}
|
||||
|
||||
|
||||
+16
-12
@@ -37,6 +37,9 @@
|
||||
#include "framerate_type.h"
|
||||
#include "aircraft_cmd.h"
|
||||
#include "vehicle_cmd.h"
|
||||
#include "script/api/script_event_types.hpp"
|
||||
|
||||
#include "widgets/vehicle_widget.h"
|
||||
|
||||
#include "table/strings.h"
|
||||
|
||||
@@ -152,8 +155,8 @@ static StationID FindNearestHangar(const Aircraft *v)
|
||||
|
||||
/* Check if our last and next destinations can be reached from the depot airport. */
|
||||
if (max_range != 0) {
|
||||
uint last_dist = (last_dest != nullptr && last_dest->airport.tile != INVALID_TILE) ? DistanceSquare(st->airport.tile, last_dest->airport.tile) : 0;
|
||||
uint next_dist = (next_dest != nullptr && next_dest->airport.tile != INVALID_TILE) ? DistanceSquare(st->airport.tile, next_dest->airport.tile) : 0;
|
||||
uint last_dist = (last_dest != nullptr && !last_dest->airport.IsEmpty()) ? DistanceSquare(st->airport.tile, last_dest->airport.tile) : 0;
|
||||
uint next_dist = (next_dest != nullptr && !next_dest->airport.IsEmpty()) ? DistanceSquare(st->airport.tile, next_dest->airport.tile) : 0;
|
||||
if (last_dist > max_range || next_dist > max_range) continue;
|
||||
}
|
||||
|
||||
@@ -832,7 +835,7 @@ static uint8_t AircraftGetEntryPoint(const Aircraft *v, const AirportFTAClass *a
|
||||
const Station *st = Station::GetIfValid(v->targetairport);
|
||||
if (st != nullptr) {
|
||||
/* Make sure we don't go to INVALID_TILE if the airport has been removed. */
|
||||
tile = (st->airport.tile != INVALID_TILE) ? st->airport.tile : st->xy;
|
||||
tile = !st->airport.IsEmpty() ? st->airport.tile : st->xy;
|
||||
}
|
||||
|
||||
int delta_x = v->x_pos - TileX(tile) * TILE_SIZE;
|
||||
@@ -869,7 +872,7 @@ static bool AircraftController(Aircraft *v)
|
||||
Direction rotation = Direction::N;
|
||||
uint size_x = 1, size_y = 1;
|
||||
if (st != nullptr) {
|
||||
if (st->airport.tile != INVALID_TILE) {
|
||||
if (!st->airport.IsEmpty()) {
|
||||
tile = st->airport.tile;
|
||||
rotation = st->airport.rotation;
|
||||
size_x = st->airport.w;
|
||||
@@ -882,7 +885,7 @@ static bool AircraftController(Aircraft *v)
|
||||
const AirportFTAClass *afc = tile == INVALID_TILE ? GetAirport(AT_DUMMY) : st->airport.GetFTA();
|
||||
|
||||
/* prevent going to INVALID_TILE if airport is deleted. */
|
||||
if (st == nullptr || st->airport.tile == INVALID_TILE) {
|
||||
if (st == nullptr || st->airport.IsEmpty()) {
|
||||
/* Jump into our "holding pattern" state machine if possible */
|
||||
if (v->pos >= afc->nofelements) {
|
||||
v->pos = v->previous_pos = AircraftGetEntryPoint(v, afc, Direction::N);
|
||||
@@ -1141,7 +1144,7 @@ static bool AircraftController(Aircraft *v)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (st->airport.tile == INVALID_TILE) {
|
||||
if (st->airport.IsEmpty()) {
|
||||
/* Airport has been removed, abort the landing procedure */
|
||||
v->state = FLYING;
|
||||
UpdateAircraftCache(v);
|
||||
@@ -1325,6 +1328,7 @@ void Aircraft::MarkDirty()
|
||||
if (this->subtype == AIR_HELICOPTER) {
|
||||
GetRotorImage(this, EngineImageType::OnMap, &this->Next()->Next()->sprite_cache.sprite_seq);
|
||||
}
|
||||
UpdateAircraftCache(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -1819,7 +1823,7 @@ static bool AirportMove(Aircraft *v, const AirportFTAClass *apc)
|
||||
{
|
||||
/* error handling */
|
||||
if (v->pos >= apc->nofelements) {
|
||||
Debug(misc, 0, "[Ap] position {} is not valid for current airport. Max position is {}", v->pos, apc->nofelements - 1);
|
||||
Debug(Facility::Misc, Severity::Critical, "[Ap] position {} is not valid for current airport. Max position is {}", v->pos, apc->nofelements - 1);
|
||||
assert(v->pos < apc->nofelements);
|
||||
}
|
||||
|
||||
@@ -1858,7 +1862,7 @@ static bool AirportMove(Aircraft *v, const AirportFTAClass *apc)
|
||||
current = current->next.get();
|
||||
} while (current != nullptr);
|
||||
|
||||
Debug(misc, 0, "[Ap] cannot move further on Airport! (pos {} state {}) for vehicle {}", v->pos, v->state, v->index);
|
||||
Debug(Facility::Misc, Severity::Critical, "[Ap] cannot move further on Airport! (pos {} state {}) for vehicle {}", v->pos, v->state, v->index);
|
||||
NOT_REACHED();
|
||||
}
|
||||
|
||||
@@ -2126,7 +2130,7 @@ static bool AircraftEventHandler(Aircraft *v, int loop)
|
||||
Station *cur_st = Station::GetIfValid(v->targetairport);
|
||||
Station *next_st = v->current_order.IsType(OT_GOTO_STATION) || v->current_order.IsType(OT_GOTO_DEPOT) ? Station::GetIfValid(v->current_order.GetDestination().ToStationID()) : nullptr;
|
||||
|
||||
if (cur_st != nullptr && cur_st->airport.tile != INVALID_TILE && next_st != nullptr && next_st->airport.tile != INVALID_TILE) {
|
||||
if (cur_st != nullptr && !cur_st->airport.IsEmpty() && next_st != nullptr && !next_st->airport.IsEmpty()) {
|
||||
uint dist = DistanceSquare(cur_st->airport.tile, next_st->airport.tile);
|
||||
AircraftHandleDestTooFar(v, dist > v->acache.cached_max_range_sqr);
|
||||
}
|
||||
@@ -2141,7 +2145,7 @@ bool Aircraft::Tick()
|
||||
{
|
||||
if (!this->IsNormalAircraft()) return true;
|
||||
|
||||
PerformanceAccumulator framerate(PFE_GL_AIRCRAFT);
|
||||
PerformanceAccumulator framerate(PerformanceElement::GameLoopAircraft);
|
||||
|
||||
this->tick_counter++;
|
||||
|
||||
@@ -2173,7 +2177,7 @@ Station *GetTargetAirportIfValid(const Aircraft *v)
|
||||
Station *st = Station::GetIfValid(v->targetairport);
|
||||
if (st == nullptr) return nullptr;
|
||||
|
||||
return st->airport.tile == INVALID_TILE ? nullptr : st;
|
||||
return st->airport.IsEmpty() ? nullptr : st;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2184,7 +2188,7 @@ void UpdateAirplanesOnNewStation(const Station *st)
|
||||
{
|
||||
/* only 1 station is updated per function call, so it is enough to get entry_point once */
|
||||
const AirportFTAClass *ap = st->airport.GetFTA();
|
||||
Direction rotation = st->airport.tile == INVALID_TILE ? Direction::N : st->airport.rotation;
|
||||
Direction rotation = st->airport.IsEmpty() ? Direction::N : st->airport.rotation;
|
||||
|
||||
for (Aircraft *v : Aircraft::Iterate()) {
|
||||
if (!v->IsNormalAircraft() || v->targetairport != st->index) continue;
|
||||
|
||||
@@ -74,7 +74,7 @@ void AddAnimatedTile(TileIndex tile, bool mark_dirty)
|
||||
*/
|
||||
void AnimateAnimatedTiles()
|
||||
{
|
||||
PerformanceAccumulator landscape_framerate(PFE_GL_LANDSCAPE);
|
||||
PerformanceAccumulator landscape_framerate(PerformanceElement::GameLoopLandscape);
|
||||
|
||||
for (auto it = std::begin(_animated_tiles); it != std::end(_animated_tiles); /* nothing */) {
|
||||
TileIndex &tile = *it;
|
||||
|
||||
@@ -357,6 +357,7 @@ void AddArticulatedParts(Vehicle *first)
|
||||
t->subtype = 0;
|
||||
t->track = front->track;
|
||||
t->railtypes = front->railtypes;
|
||||
t->flags.Set(VehicleRailFlag::AllowedOnNormalRail, _settings_game.vehicle.disable_elrails && RailVehInfo(front->engine_type)->intended_railtypes.Test(RAILTYPE_ELECTRIC));
|
||||
|
||||
t->spritenum = e_artic->VehInfo<RailVehicleInfo>().image_index;
|
||||
if (e_artic->CanCarryCargo()) {
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "order_cmd.h"
|
||||
#include "train_cmd.h"
|
||||
#include "vehicle_cmd.h"
|
||||
#include "script/api/script_event_types.hpp"
|
||||
|
||||
#include "table/strings.h"
|
||||
|
||||
@@ -357,7 +358,7 @@ static CommandCost BuildReplacementVehicle(Vehicle *old_veh, Vehicle **new_vehic
|
||||
|
||||
/* Build the new vehicle */
|
||||
VehicleID new_veh_id;
|
||||
std::tie(cost, new_veh_id, std::ignore, std::ignore, std::ignore) = Command<Commands::BuildVehicle>::Do({DoCommandFlag::Execute, DoCommandFlag::AutoReplace}, old_veh->tile, e, true, INVALID_CARGO, INVALID_CLIENT_ID);
|
||||
std::tie(cost, new_veh_id, std::ignore, std::ignore, std::ignore) = Command<Commands::BuildVehicle>::Do({DoCommandFlag::Execute, DoCommandFlag::AutoReplace}, old_veh->tile, e, true, INVALID_CARGO, ClientID::Invalid);
|
||||
if (cost.Failed()) return cost;
|
||||
|
||||
Vehicle *new_veh = Vehicle::Get(new_veh_id);
|
||||
@@ -489,11 +490,11 @@ static CommandCost ReplaceFreeUnit(Vehicle **single_unit, DoCommandFlags flags,
|
||||
}
|
||||
|
||||
/* Sell the old vehicle */
|
||||
cost.AddCost(Command<Commands::SellVehicle>::Do(flags, old_v->index, false, false, INVALID_CLIENT_ID));
|
||||
cost.AddCost(Command<Commands::SellVehicle>::Do(flags, old_v->index, false, false, ClientID::Invalid));
|
||||
|
||||
/* If we are not in DoCommandFlag::Execute undo everything */
|
||||
if (!flags.Test(DoCommandFlag::Execute)) {
|
||||
Command<Commands::SellVehicle>::Do(DoCommandFlag::Execute, new_v->index, false, false, INVALID_CLIENT_ID);
|
||||
Command<Commands::SellVehicle>::Do(DoCommandFlag::Execute, new_v->index, false, false, ClientID::Invalid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -633,7 +634,7 @@ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlags flags, bool wago
|
||||
assert(RailVehInfo(wagon->engine_type)->railveh_type == RailVehicleType::Wagon);
|
||||
|
||||
/* Sell wagon */
|
||||
[[maybe_unused]] CommandCost ret = Command<Commands::SellVehicle>::Do(DoCommandFlag::Execute, wagon->index, false, false, INVALID_CLIENT_ID);
|
||||
[[maybe_unused]] CommandCost ret = Command<Commands::SellVehicle>::Do(DoCommandFlag::Execute, wagon->index, false, false, ClientID::Invalid);
|
||||
assert(ret.Succeeded());
|
||||
it->new_veh = nullptr;
|
||||
|
||||
@@ -665,7 +666,7 @@ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlags flags, bool wago
|
||||
/* Sell the vehicle.
|
||||
* Note: This might temporarily construct new trains, so use DoCommandFlag::AutoReplace to prevent
|
||||
* it from failing due to engine limits. */
|
||||
cost.AddCost(Command<Commands::SellVehicle>::Do(DoCommandFlags{flags}.Set(DoCommandFlag::AutoReplace), w->index, false, false, INVALID_CLIENT_ID));
|
||||
cost.AddCost(Command<Commands::SellVehicle>::Do(DoCommandFlags{flags}.Set(DoCommandFlag::AutoReplace), w->index, false, false, ClientID::Invalid));
|
||||
if (flags.Test(DoCommandFlag::Execute)) {
|
||||
it->old_veh = nullptr;
|
||||
if (it == std::begin(replacements)) old_head = nullptr;
|
||||
@@ -696,7 +697,7 @@ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlags flags, bool wago
|
||||
if (!flags.Test(DoCommandFlag::Execute)) {
|
||||
for (auto it = std::rbegin(replacements); it != std::rend(replacements); ++it) {
|
||||
if (it->new_veh != nullptr) {
|
||||
Command<Commands::SellVehicle>::Do(DoCommandFlag::Execute, it->new_veh->index, false, false, INVALID_CLIENT_ID);
|
||||
Command<Commands::SellVehicle>::Do(DoCommandFlag::Execute, it->new_veh->index, false, false, ClientID::Invalid);
|
||||
it->new_veh = nullptr;
|
||||
}
|
||||
}
|
||||
@@ -723,12 +724,12 @@ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlags flags, bool wago
|
||||
}
|
||||
|
||||
/* Sell the old vehicle */
|
||||
cost.AddCost(Command<Commands::SellVehicle>::Do(flags, old_head->index, false, false, INVALID_CLIENT_ID));
|
||||
cost.AddCost(Command<Commands::SellVehicle>::Do(flags, old_head->index, false, false, ClientID::Invalid));
|
||||
}
|
||||
|
||||
/* If we are not in DoCommandFlag::Execute undo everything */
|
||||
if (!flags.Test(DoCommandFlag::Execute)) {
|
||||
Command<Commands::SellVehicle>::Do(DoCommandFlag::Execute, new_head->index, false, false, INVALID_CLIENT_ID);
|
||||
Command<Commands::SellVehicle>::Do(DoCommandFlag::Execute, new_head->index, false, false, ClientID::Invalid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -450,7 +450,7 @@ public:
|
||||
str = GetString(STR_REPLACE_NOT_REPLACING_VEHICLE_SELECTED);
|
||||
}
|
||||
|
||||
DrawString(r.Shrink(WidgetDimensions::scaled.frametext, WidgetDimensions::scaled.framerect), std::move(str), TextColour::Black, SA_HOR_CENTER);
|
||||
DrawString(r.Shrink(WidgetDimensions::scaled.frametext, WidgetDimensions::scaled.framerect), std::move(str), TextColour::Black, AlignmentH::Centre);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#ifndef BASE_MEDIA_BASE_H
|
||||
#define BASE_MEDIA_BASE_H
|
||||
|
||||
#include "debug_type.h"
|
||||
#include "fileio_func.h"
|
||||
#include "textfile_type.h"
|
||||
#include "textfile_gui.h"
|
||||
@@ -93,7 +94,7 @@ struct BaseSet {
|
||||
return BaseSet<T>::NUM_FILES - this->valid_files;
|
||||
}
|
||||
|
||||
void LogError(std::string_view full_filename, std::string_view detail, int level = 0) const;
|
||||
void LogError(std::string_view full_filename, std::string_view detail, Severity severity = {}) const;
|
||||
const IniItem *GetMandatoryItem(std::string_view full_filename, const IniGroup &group, std::string_view name) const;
|
||||
|
||||
bool FillSetDetails(const IniFile &ini, const std::string &path, const std::string &full_filename, bool allow_empty_filename = true);
|
||||
|
||||
+33
-19
@@ -21,13 +21,13 @@ extern void CheckExternalFiles();
|
||||
* Log error from reading basesets.
|
||||
* @param full_filename the full filename of the loaded file
|
||||
* @param detail detail log message
|
||||
* @param level debug level
|
||||
* @param severity debug severity
|
||||
*/
|
||||
template <class T>
|
||||
void BaseSet<T>::LogError(std::string_view full_filename, std::string_view detail, int level) const
|
||||
void BaseSet<T>::LogError(std::string_view full_filename, std::string_view detail, Severity severity) const
|
||||
{
|
||||
Debug(misc, level, "Loading base {}set details failed: {}", BaseSet<T>::SET_TYPE, full_filename);
|
||||
Debug(misc, level, " {}", detail);
|
||||
Debug(Facility::Misc, severity, "Loading base {}set details failed: {}", BaseSet<T>::SET_TYPE, full_filename);
|
||||
Debug(Facility::Misc, severity, " {}", detail);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -47,6 +47,22 @@ const IniItem *BaseSet<T>::GetMandatoryItem(std::string_view full_filename, cons
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to decode a 4 character short name into an uint32_t representation.
|
||||
* @param shortname The short name.
|
||||
* @return The uint32_t representation.
|
||||
*/
|
||||
constexpr uint32_t DecodeShortName(std::string_view shortname)
|
||||
{
|
||||
/* The short name is documented to be exactly 4 characters long, see docs/ob[gms]_format.txt. */
|
||||
shortname = shortname.substr(0, 4);
|
||||
uint32_t encoded = 0;
|
||||
for (size_t i = 0; i < shortname.size(); i++) {
|
||||
encoded |= static_cast<uint8_t>(shortname[i]) << (i * 8);
|
||||
}
|
||||
return encoded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the set information from a loaded ini.
|
||||
* @param ini the ini to read from
|
||||
@@ -85,9 +101,7 @@ bool BaseSet<T>::FillSetDetails(const IniFile &ini, const std::string &path, con
|
||||
|
||||
item = this->GetMandatoryItem(full_filename, *metadata, "shortname");
|
||||
if (item == nullptr) return false;
|
||||
for (uint i = 0; (*item->value)[i] != '\0' && i < 4; i++) {
|
||||
this->shortname |= ((uint8_t)(*item->value)[i]) << (i * 8);
|
||||
}
|
||||
this->shortname = DecodeShortName(*item->value);
|
||||
|
||||
item = this->GetMandatoryItem(full_filename, *metadata, "version");
|
||||
if (item == nullptr) return false;
|
||||
@@ -111,10 +125,10 @@ bool BaseSet<T>::FillSetDetails(const IniFile &ini, const std::string &path, con
|
||||
const IniGroup *origin = ini.GetGroup("origin");
|
||||
auto file_names = BaseSet<T>::GetFilenames();
|
||||
bool original_set =
|
||||
std::byteswap(this->shortname) == 'TTDD' || // TTD DOS graphics, TTD DOS music
|
||||
std::byteswap(this->shortname) == 'TTDW' || // TTD WIN graphics, TTD WIN music
|
||||
std::byteswap(this->shortname) == 'TTDO' || // TTD sound
|
||||
std::byteswap(this->shortname) == 'TTOD'; // TTO music
|
||||
this->shortname == DecodeShortName("TTDD") || // TTD DOS graphics, TTD DOS music
|
||||
this->shortname == DecodeShortName("TTDW") || // TTD WIN graphics, TTD WIN music
|
||||
this->shortname == DecodeShortName("TTDO") || // TTD sound
|
||||
this->shortname == DecodeShortName("TTOD"); // TTO music
|
||||
|
||||
for (uint i = 0; i < BaseSet<T>::NUM_FILES; i++) {
|
||||
MD5File *file = &this->files[i];
|
||||
@@ -151,7 +165,7 @@ bool BaseSet<T>::FillSetDetails(const IniFile &ini, const std::string &path, con
|
||||
item = origin != nullptr ? origin->GetItem(filename) : nullptr;
|
||||
if (item == nullptr) item = origin != nullptr ? origin->GetItem("default") : nullptr;
|
||||
if (item == nullptr || !item->value.has_value()) {
|
||||
this->LogError(full_filename, fmt::format("origin.{} field missing", filename), 1);
|
||||
this->LogError(full_filename, fmt::format("origin.{} field missing", filename), Severity::Error);
|
||||
file->missing_warning.clear();
|
||||
} else {
|
||||
file->missing_warning = item->value.value();
|
||||
@@ -169,13 +183,13 @@ bool BaseSet<T>::FillSetDetails(const IniFile &ini, const std::string &path, con
|
||||
|
||||
case MD5File::ChecksumResult::Mismatch:
|
||||
/* This is normal for original sample.cat, which either matches with orig_dos or orig_win. */
|
||||
this->LogError(full_filename, fmt::format("MD5 checksum mismatch for: {}", filename), original_set ? 1 : 0);
|
||||
this->LogError(full_filename, fmt::format("MD5 checksum mismatch for: {}", filename), original_set ? Severity::Error : Severity::Critical);
|
||||
this->found_files++;
|
||||
break;
|
||||
|
||||
case MD5File::ChecksumResult::NoFile:
|
||||
/* Missing files is normal for the original basesets. Use lower debug level */
|
||||
this->LogError(full_filename, fmt::format("File is missing: {}", filename), original_set ? 1 : 0);
|
||||
this->LogError(full_filename, fmt::format("File is missing: {}", filename), original_set ? Severity::Error : Severity::Critical);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -186,7 +200,7 @@ bool BaseSet<T>::FillSetDetails(const IniFile &ini, const std::string &path, con
|
||||
template <class Tbase_set>
|
||||
bool BaseMedia<Tbase_set>::AddFile(const std::string &filename, size_t basepath_length, const std::string &)
|
||||
{
|
||||
Debug(misc, 1, "Checking {} for base {} set", filename, BaseSet<Tbase_set>::SET_TYPE);
|
||||
Debug(Facility::Misc, Severity::Error, "Checking {} for base {} set", filename, BaseSet<Tbase_set>::SET_TYPE);
|
||||
|
||||
auto set = std::make_unique<Tbase_set>();
|
||||
IniFile ini{};
|
||||
@@ -208,7 +222,7 @@ bool BaseMedia<Tbase_set>::AddFile(const std::string &filename, size_t basepath_
|
||||
if (((*existing)->valid_files == set->valid_files && (*existing)->version >= set->version) ||
|
||||
(*existing)->valid_files > set->valid_files) {
|
||||
|
||||
Debug(misc, 1, "Not adding {} ({}) as base {} set (duplicate, {})", set->name, fmt::join(set->version, "."),
|
||||
Debug(Facility::Misc, Severity::Error, "Not adding {} ({}) as base {} set (duplicate, {})", set->name, fmt::join(set->version, "."),
|
||||
BaseSet<Tbase_set>::SET_TYPE,
|
||||
(*existing)->valid_files > set->valid_files ? "fewer valid files" : "lower version");
|
||||
|
||||
@@ -224,16 +238,16 @@ bool BaseMedia<Tbase_set>::AddFile(const std::string &filename, size_t basepath_
|
||||
/* Keep baseset configuration, if compatible */
|
||||
set->CopyCompatibleConfig(**existing);
|
||||
|
||||
Debug(misc, 1, "Removing {} ({}) as base {} set (duplicate, {})", (*existing)->name, fmt::join((*existing)->version, "."), BaseSet<Tbase_set>::SET_TYPE,
|
||||
Debug(Facility::Misc, Severity::Error, "Removing {} ({}) as base {} set (duplicate, {})", (*existing)->name, fmt::join((*existing)->version, "."), BaseSet<Tbase_set>::SET_TYPE,
|
||||
(*existing)->valid_files < set->valid_files ? "fewer valid files" : "lower version");
|
||||
|
||||
/* Existing set is worse, move it to duplicates and replace with the current set. */
|
||||
duplicate_sets.push_back(std::move(*existing));
|
||||
|
||||
Debug(misc, 1, "Adding {} ({}) as base {} set", set->name, fmt::join(set->version, "."), BaseSet<Tbase_set>::SET_TYPE);
|
||||
Debug(Facility::Misc, Severity::Error, "Adding {} ({}) as base {} set", set->name, fmt::join(set->version, "."), BaseSet<Tbase_set>::SET_TYPE);
|
||||
*existing = std::move(set);
|
||||
} else {
|
||||
Debug(grf, 1, "Adding {} ({}) as base {} set", set->name, set->version, BaseSet<Tbase_set>::SET_TYPE);
|
||||
Debug(Facility::Misc, Severity::Error, "Adding {} ({}) as base {} set", set->name, set->version, BaseSet<Tbase_set>::SET_TYPE);
|
||||
available_sets.push_back(std::move(set));
|
||||
}
|
||||
|
||||
|
||||
+2
-24
@@ -22,7 +22,7 @@ extern StationPool _station_pool;
|
||||
template <typename T>
|
||||
struct SpecMapping {
|
||||
const T *spec = nullptr; ///< Custom spec.
|
||||
uint32_t grfid = 0; ///< GRF ID of this custom spec.
|
||||
GrfID grfid{}; ///< GRF ID of this custom spec.
|
||||
uint16_t localidx = 0; ///< Local ID within GRF of this custom spec.
|
||||
};
|
||||
|
||||
@@ -32,28 +32,6 @@ struct RoadStopTileData {
|
||||
uint8_t animation_frame = 0;
|
||||
};
|
||||
|
||||
/** StationRect - used to track station spread out rectangle - cheaper than scanning whole map */
|
||||
struct StationRect : public Rect {
|
||||
enum StationRectMode : uint8_t {
|
||||
ADD_TEST = 0,
|
||||
ADD_TRY,
|
||||
ADD_FORCE
|
||||
};
|
||||
|
||||
StationRect();
|
||||
void MakeEmpty();
|
||||
bool PtInExtendedRect(int x, int y, int distance = 0) const;
|
||||
bool IsEmpty() const;
|
||||
CommandCost BeforeAddTile(TileIndex tile, StationRectMode mode);
|
||||
CommandCost BeforeAddRect(TileIndex tile, int w, int h, StationRectMode mode);
|
||||
bool AfterRemoveTile(BaseStation *st, TileIndex tile);
|
||||
bool AfterRemoveRect(BaseStation *st, TileArea ta);
|
||||
|
||||
static bool ScanForStationTiles(StationID st_id, int left_a, int top_a, int right_a, int bottom_a);
|
||||
|
||||
StationRect& operator = (const Rect &src);
|
||||
};
|
||||
|
||||
/** Base class for all station-ish types */
|
||||
struct BaseStation : StationPool::PoolItem<&_station_pool> {
|
||||
TileIndex xy = INVALID_TILE; ///< Base tile of the station
|
||||
@@ -82,7 +60,7 @@ struct BaseStation : StationPool::PoolItem<&_station_pool> {
|
||||
CargoTypes cached_roadstop_cargo_triggers{}; ///< NOSAVE: Combined cargo trigger bitmask for road stops
|
||||
|
||||
TileArea train_station{INVALID_TILE, 0, 0}; ///< Tile area the train 'station' part covers
|
||||
StationRect rect{}; ///< NOSAVE: Station spread out rectangle maintained by StationRect::xxx() functions
|
||||
TileArea spread{}; ///< NOSAVE: Station spread tile area.
|
||||
|
||||
std::vector<RoadStopTileData> custom_roadstop_tile_data{}; ///< List of custom road stop tile data
|
||||
|
||||
|
||||
@@ -50,19 +50,6 @@ public:
|
||||
this->data.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the BitmapTileArea with the specified Rect.
|
||||
* @param r Rect to use.
|
||||
*/
|
||||
void Initialize(const Rect &r)
|
||||
{
|
||||
this->tile = TileXY(r.left, r.top);
|
||||
this->w = r.Width();
|
||||
this->h = r.Height();
|
||||
this->data.clear();
|
||||
this->data.resize(Index(w, h));
|
||||
}
|
||||
|
||||
void Initialize(const TileArea &ta)
|
||||
{
|
||||
this->tile = ta.tile;
|
||||
@@ -125,11 +112,6 @@ public:
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::unique_ptr<TileIterator> Clone() const override
|
||||
{
|
||||
return std::make_unique<BitmapTileIterator>(*this);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* BITMAP_TYPE_HPP */
|
||||
|
||||
@@ -318,7 +318,7 @@ void Blitter_32bppAnim::DrawColourMappingRect(void *dst, int width, int height,
|
||||
return;
|
||||
}
|
||||
|
||||
Debug(misc, 0, "32bpp blitter doesn't know how to draw this colour table ('{}')", pal);
|
||||
Debug(Facility::Misc, Severity::Critical, "32bpp blitter doesn't know how to draw this colour table ('{}')", pal);
|
||||
}
|
||||
|
||||
void Blitter_32bppAnim::SetPixel(void *video, int x, int y, PixelColour colour)
|
||||
|
||||
@@ -43,7 +43,7 @@ inline void Blitter_32bppSSE4_Anim::Draw(const BlitterParams *bp, ZoomLevel zoom
|
||||
const MapValue *src_mv_line = (const MapValue *) &sd->data[si->mv_offset] + bp->skip_top * si->sprite_width;
|
||||
const Colour *src_rgba_line = (const Colour *) ((const uint8_t *) &sd->data[si->sprite_offset] + bp->skip_top * si->sprite_line_size);
|
||||
|
||||
if (read_mode != RM_WITH_MARGIN) {
|
||||
if (read_mode != ReadMode::WithMargin) {
|
||||
src_rgba_line += bp->skip_left;
|
||||
src_mv_line += bp->skip_left;
|
||||
}
|
||||
@@ -61,8 +61,8 @@ inline void Blitter_32bppSSE4_Anim::Draw(const BlitterParams *bp, ZoomLevel zoom
|
||||
if (mode != BlitterMode::Transparent) src_mv = src_mv_line;
|
||||
uint16_t *anim = anim_line;
|
||||
|
||||
if (read_mode == RM_WITH_MARGIN) {
|
||||
assert(bt_last == BT_NONE); // or you must ensure block type is preserved
|
||||
if (read_mode == ReadMode::WithMargin) {
|
||||
assert(bt_last == BlockType::None); // or you must ensure block type is preserved
|
||||
anim += src_rgba_line[0].data;
|
||||
src += src_rgba_line[0].data;
|
||||
dst += src_rgba_line[0].data;
|
||||
@@ -155,7 +155,7 @@ bmno_full_transparency:
|
||||
dst += 2;
|
||||
}
|
||||
|
||||
if ((bt_last == BT_NONE && effective_width & 1) || bt_last == BT_ODD) {
|
||||
if ((bt_last == BlockType::None && effective_width & 1) || bt_last == BlockType::Odd) {
|
||||
if (src->a == 0) {
|
||||
/* Complete transparency. */
|
||||
} else if (src->a == 255) {
|
||||
@@ -266,7 +266,7 @@ bmcr_full_transparency:
|
||||
anim += 2;
|
||||
}
|
||||
|
||||
if ((bt_last == BT_NONE && effective_width & 1) || bt_last == BT_ODD) {
|
||||
if ((bt_last == BlockType::None && effective_width & 1) || bt_last == BlockType::Odd) {
|
||||
/* In case the m-channel is zero, do not remap this pixel in any way. */
|
||||
__m128i srcABCD;
|
||||
if (src->a == 0) break;
|
||||
@@ -309,7 +309,7 @@ bmcr_alpha_blend_single:
|
||||
if (src[-1].a) anim[-1] = 0;
|
||||
}
|
||||
|
||||
if ((bt_last == BT_NONE && bp->width & 1) || bt_last == BT_ODD) {
|
||||
if ((bt_last == BlockType::None && bp->width & 1) || bt_last == BlockType::Odd) {
|
||||
__m128i srcABCD = _mm_cvtsi32_si128(src->data);
|
||||
__m128i dstABCD = _mm_cvtsi32_si128(dst->data);
|
||||
dst->data = _mm_cvtsi128_si32(DarkenTwoPixels(srcABCD, dstABCD, a_cm, tr_nom_base));
|
||||
@@ -373,6 +373,25 @@ next_line:
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a sprite to a (screen) buffer. It is templated to allow faster operation.
|
||||
*
|
||||
* @tparam mode blitter mode
|
||||
* @param bp further blitting parameters
|
||||
* @param zoom zoom level at which we are drawing
|
||||
* @param animated Whether the sprite is animated.
|
||||
*/
|
||||
template <BlitterMode mode, Blitter_32bppSSE_Base::ReadMode read_mode, Blitter_32bppSSE_Base::BlockType bt_last, bool translucent>
|
||||
inline void Blitter_32bppSSE4_Anim::Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom, bool animated)
|
||||
{
|
||||
if (animated) {
|
||||
this->Draw<mode, read_mode, bt_last, translucent, true>(bp, zoom);
|
||||
} else {
|
||||
this->Draw<mode, read_mode, bt_last, translucent, false>(bp, zoom);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Draws a sprite to a (screen) buffer. Calls adequate templated function.
|
||||
*
|
||||
@@ -394,25 +413,20 @@ void Blitter_32bppSSE4_Anim::Draw(Blitter::BlitterParams *bp, BlitterMode mode,
|
||||
bm_normal:
|
||||
if (bp->skip_left != 0 || bp->width <= MARGIN_NORMAL_THRESHOLD) {
|
||||
const BlockType bt_last = (BlockType) (bp->width & 1);
|
||||
if (bt_last == BT_EVEN) {
|
||||
if (sprite_flags.Test(SpriteFlag::NoAnim)) Draw<BlitterMode::Normal, RM_WITH_SKIP, BT_EVEN, true, false>(bp, zoom);
|
||||
else Draw<BlitterMode::Normal, RM_WITH_SKIP, BT_EVEN, true, true>(bp, zoom);
|
||||
if (bt_last == BlockType::Even) {
|
||||
Draw<BlitterMode::Normal, ReadMode::WithSkip, BlockType::Even, true>(bp, zoom, !sprite_flags.Test(SpriteFlag::NoAnim));
|
||||
} else {
|
||||
if (sprite_flags.Test(SpriteFlag::NoAnim)) Draw<BlitterMode::Normal, RM_WITH_SKIP, BT_ODD, true, false>(bp, zoom);
|
||||
else Draw<BlitterMode::Normal, RM_WITH_SKIP, BT_ODD, true, true>(bp, zoom);
|
||||
Draw<BlitterMode::Normal, ReadMode::WithSkip, BlockType::Odd, true>(bp, zoom, !sprite_flags.Test(SpriteFlag::NoAnim));
|
||||
}
|
||||
} else {
|
||||
#ifdef POINTER_IS_64BIT
|
||||
if (sprite_flags.Test(SpriteFlag::Translucent)) {
|
||||
if (sprite_flags.Test(SpriteFlag::NoAnim)) Draw<BlitterMode::Normal, RM_WITH_MARGIN, BT_NONE, true, false>(bp, zoom);
|
||||
else Draw<BlitterMode::Normal, RM_WITH_MARGIN, BT_NONE, true, true>(bp, zoom);
|
||||
Draw<BlitterMode::Normal, ReadMode::WithMargin, BlockType::None, true>(bp, zoom, !sprite_flags.Test(SpriteFlag::NoAnim));
|
||||
} else {
|
||||
if (sprite_flags.Test(SpriteFlag::NoAnim)) Draw<BlitterMode::Normal, RM_WITH_MARGIN, BT_NONE, false, false>(bp, zoom);
|
||||
else Draw<BlitterMode::Normal, RM_WITH_MARGIN, BT_NONE, false, true>(bp, zoom);
|
||||
Draw<BlitterMode::Normal, ReadMode::WithMargin, BlockType::None, false>(bp, zoom, !sprite_flags.Test(SpriteFlag::NoAnim));
|
||||
}
|
||||
#else
|
||||
if (sprite_flags.Test(SpriteFlag::NoAnim)) Draw<BlitterMode::Normal, RM_WITH_MARGIN, BT_NONE, true, false>(bp, zoom);
|
||||
else Draw<BlitterMode::Normal, RM_WITH_MARGIN, BT_NONE, true, true>(bp, zoom);
|
||||
Draw<BlitterMode::Normal, ReadMode::WithMargin, BlockType::None, true>(bp, zoom, !sprite_flags.Test(SpriteFlag::NoAnim));
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
@@ -420,17 +434,15 @@ bm_normal:
|
||||
case BlitterMode::ColourRemap:
|
||||
if (sprite_flags.Test(SpriteFlag::NoRemap)) goto bm_normal;
|
||||
if (bp->skip_left != 0 || bp->width <= MARGIN_REMAP_THRESHOLD) {
|
||||
if (sprite_flags.Test(SpriteFlag::NoAnim)) Draw<BlitterMode::ColourRemap, RM_WITH_SKIP, BT_NONE, true, false>(bp, zoom);
|
||||
else Draw<BlitterMode::ColourRemap, RM_WITH_SKIP, BT_NONE, true, true>(bp, zoom);
|
||||
Draw<BlitterMode::ColourRemap, ReadMode::WithSkip, BlockType::None, true>(bp, zoom, !sprite_flags.Test(SpriteFlag::NoAnim));
|
||||
} else {
|
||||
if (sprite_flags.Test(SpriteFlag::NoAnim)) Draw<BlitterMode::ColourRemap, RM_WITH_MARGIN, BT_NONE, true, false>(bp, zoom);
|
||||
else Draw<BlitterMode::ColourRemap, RM_WITH_MARGIN, BT_NONE, true, true>(bp, zoom);
|
||||
Draw<BlitterMode::ColourRemap, ReadMode::WithMargin, BlockType::None, true>(bp, zoom, !sprite_flags.Test(SpriteFlag::NoAnim));
|
||||
}
|
||||
break;
|
||||
case BlitterMode::Transparent: Draw<BlitterMode::Transparent, RM_NONE, BT_NONE, true, true>(bp, zoom); return;
|
||||
case BlitterMode::TransparentRemap: Draw<BlitterMode::TransparentRemap, RM_NONE, BT_NONE, true, true>(bp, zoom); return;
|
||||
case BlitterMode::CrashRemap: Draw<BlitterMode::CrashRemap, RM_NONE, BT_NONE, true, true>(bp, zoom); return;
|
||||
case BlitterMode::BlackRemap: Draw<BlitterMode::BlackRemap, RM_NONE, BT_NONE, true, true>(bp, zoom); return;
|
||||
case BlitterMode::Transparent: Draw<BlitterMode::Transparent, ReadMode::None, BlockType::None, true, true>(bp, zoom); return;
|
||||
case BlitterMode::TransparentRemap: Draw<BlitterMode::TransparentRemap, ReadMode::None, BlockType::None, true, true>(bp, zoom); return;
|
||||
case BlitterMode::CrashRemap: Draw<BlitterMode::CrashRemap, ReadMode::None, BlockType::None, true, true>(bp, zoom); return;
|
||||
case BlitterMode::BlackRemap: Draw<BlitterMode::BlackRemap, ReadMode::None, BlockType::None, true, true>(bp, zoom); return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,8 @@ private:
|
||||
public:
|
||||
template <BlitterMode mode, Blitter_32bppSSE_Base::ReadMode read_mode, Blitter_32bppSSE_Base::BlockType bt_last, bool translucent, bool animated>
|
||||
void Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom);
|
||||
template <BlitterMode mode, Blitter_32bppSSE_Base::ReadMode read_mode, Blitter_32bppSSE_Base::BlockType bt_last, bool translucent>
|
||||
void Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom, bool animated);
|
||||
void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) override;
|
||||
|
||||
Sprite *Encode(SpriteType sprite_type, const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator) override
|
||||
|
||||
@@ -112,7 +112,7 @@ void Blitter_32bppSimple::DrawColourMappingRect(void *dst, int width, int height
|
||||
return;
|
||||
}
|
||||
|
||||
Debug(misc, 0, "32bpp blitter doesn't know how to draw this colour table ('{}')", pal);
|
||||
Debug(Facility::Misc, Severity::Critical, "32bpp blitter doesn't know how to draw this colour table ('{}')", pal);
|
||||
}
|
||||
|
||||
Sprite *Blitter_32bppSimple::Encode(SpriteType, const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator)
|
||||
|
||||
@@ -39,17 +39,17 @@ public:
|
||||
static_assert(sizeof(MapValue) == 2);
|
||||
|
||||
/** Helper for creating specialised functions for specific optimisations. */
|
||||
enum ReadMode : uint8_t {
|
||||
RM_WITH_SKIP, ///< Use normal code for skipping empty pixels.
|
||||
RM_WITH_MARGIN, ///< Use cached number of empty pixels at begin and end of line to reduce work.
|
||||
RM_NONE, ///< No specialisation.
|
||||
enum class ReadMode : uint8_t {
|
||||
WithSkip, ///< Use normal code for skipping empty pixels.
|
||||
WithMargin, ///< Use cached number of empty pixels at begin and end of line to reduce work.
|
||||
None, ///< No specialisation.
|
||||
};
|
||||
|
||||
/** Helper for creating specialised functions for the case where the sprite width is odd or even. */
|
||||
enum BlockType : uint8_t {
|
||||
BT_EVEN, ///< An even number of pixels in the width; no need for a special case for the last pixel.
|
||||
BT_ODD, ///< An odd number of pixels in the width; special case for the last pixel.
|
||||
BT_NONE, ///< No specialisation for either case.
|
||||
enum class BlockType : uint8_t {
|
||||
Even, ///< An even number of pixels in the width; no need for a special case for the last pixel.
|
||||
Odd, ///< An odd number of pixels in the width; special case for the last pixel.
|
||||
None, ///< No specialisation for either case.
|
||||
};
|
||||
|
||||
/** Helper for using specialised functions designed to prevent whenever it's possible things like:
|
||||
|
||||
@@ -231,7 +231,7 @@ inline void Blitter_32bppSSE4::Draw(const Blitter::BlitterParams *bp, ZoomLevel
|
||||
const MapValue *src_mv_line = (const MapValue *) &sd->data[si->mv_offset] + bp->skip_top * si->sprite_width;
|
||||
const Colour *src_rgba_line = (const Colour *) ((const uint8_t *) &sd->data[si->sprite_offset] + bp->skip_top * si->sprite_line_size);
|
||||
|
||||
if (read_mode != RM_WITH_MARGIN) {
|
||||
if (read_mode != ReadMode::WithMargin) {
|
||||
src_rgba_line += bp->skip_left;
|
||||
src_mv_line += bp->skip_left;
|
||||
}
|
||||
@@ -261,8 +261,8 @@ inline void Blitter_32bppSSE4::Draw(const Blitter::BlitterParams *bp, ZoomLevel
|
||||
const Colour *src = src_rgba_line + META_LENGTH;
|
||||
if (mode == BlitterMode::ColourRemap || mode == BlitterMode::CrashRemap) src_mv = src_mv_line;
|
||||
|
||||
if (read_mode == RM_WITH_MARGIN) {
|
||||
assert(bt_last == BT_NONE); // or you must ensure block type is preserved
|
||||
if (read_mode == ReadMode::WithMargin) {
|
||||
assert(bt_last == BlockType::None); // or you must ensure block type is preserved
|
||||
src += src_rgba_line[0].data;
|
||||
dst += src_rgba_line[0].data;
|
||||
if (mode == BlitterMode::ColourRemap || mode == BlitterMode::CrashRemap) src_mv += src_rgba_line[0].data;
|
||||
@@ -293,7 +293,7 @@ inline void Blitter_32bppSSE4::Draw(const Blitter::BlitterParams *bp, ZoomLevel
|
||||
dst += 2;
|
||||
}
|
||||
|
||||
if ((bt_last == BT_NONE && effective_width & 1) || bt_last == BT_ODD) {
|
||||
if ((bt_last == BlockType::None && effective_width & 1) || bt_last == BlockType::Odd) {
|
||||
__m128i srcABCD = _mm_cvtsi32_si128(src->data);
|
||||
__m128i dstABCD = _mm_cvtsi32_si128(dst->data);
|
||||
dst->data = _mm_cvtsi128_si32(AlphaBlendTwoPixels(srcABCD, dstABCD, ALPHA_BLEND_PARAM_1, ALPHA_BLEND_PARAM_2, ALPHA_BLEND_PARAM_3));
|
||||
@@ -347,7 +347,7 @@ inline void Blitter_32bppSSE4::Draw(const Blitter::BlitterParams *bp, ZoomLevel
|
||||
src_mv += 2;
|
||||
}
|
||||
|
||||
if ((bt_last == BT_NONE && effective_width & 1) || bt_last == BT_ODD) {
|
||||
if ((bt_last == BlockType::None && effective_width & 1) || bt_last == BlockType::Odd) {
|
||||
#else
|
||||
for (uint x = (uint) effective_width; x > 0; x--) {
|
||||
#endif
|
||||
@@ -392,7 +392,7 @@ bmcr_alpha_blend_single:
|
||||
dst += 2;
|
||||
}
|
||||
|
||||
if ((bt_last == BT_NONE && bp->width & 1) || bt_last == BT_ODD) {
|
||||
if ((bt_last == BlockType::None && bp->width & 1) || bt_last == BlockType::Odd) {
|
||||
__m128i srcABCD = _mm_cvtsi32_si128(src->data);
|
||||
__m128i dstABCD = _mm_cvtsi32_si128(dst->data);
|
||||
dst->data = _mm_cvtsi128_si32(DarkenTwoPixels(srcABCD, dstABCD, DARKEN_PARAM_1, DARKEN_PARAM_2));
|
||||
@@ -468,14 +468,14 @@ void Blitter_32bppSSE4::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomL
|
||||
bm_normal:
|
||||
const BlockType bt_last = (BlockType) (bp->width & 1);
|
||||
switch (bt_last) {
|
||||
default: Draw<BlitterMode::Normal, RM_WITH_SKIP, BT_EVEN, true>(bp, zoom); return;
|
||||
case BT_ODD: Draw<BlitterMode::Normal, RM_WITH_SKIP, BT_ODD, true>(bp, zoom); return;
|
||||
default: Draw<BlitterMode::Normal, ReadMode::WithSkip, BlockType::Even, true>(bp, zoom); return;
|
||||
case BlockType::Odd: Draw<BlitterMode::Normal, ReadMode::WithSkip, BlockType::Odd, true>(bp, zoom); return;
|
||||
}
|
||||
} else {
|
||||
if (((const Blitter_32bppSSE_Base::SpriteData *) bp->sprite)->flags.Test(SpriteFlag::Translucent)) {
|
||||
Draw<BlitterMode::Normal, RM_WITH_MARGIN, BT_NONE, true>(bp, zoom);
|
||||
Draw<BlitterMode::Normal, ReadMode::WithMargin, BlockType::None, true>(bp, zoom);
|
||||
} else {
|
||||
Draw<BlitterMode::Normal, RM_WITH_MARGIN, BT_NONE, false>(bp, zoom);
|
||||
Draw<BlitterMode::Normal, ReadMode::WithMargin, BlockType::None, false>(bp, zoom);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -484,14 +484,14 @@ bm_normal:
|
||||
case BlitterMode::ColourRemap:
|
||||
if (((const Blitter_32bppSSE_Base::SpriteData *) bp->sprite)->flags.Test(SpriteFlag::NoRemap)) goto bm_normal;
|
||||
if (bp->skip_left != 0 || bp->width <= MARGIN_REMAP_THRESHOLD) {
|
||||
Draw<BlitterMode::ColourRemap, RM_WITH_SKIP, BT_NONE, true>(bp, zoom); return;
|
||||
Draw<BlitterMode::ColourRemap, ReadMode::WithSkip, BlockType::None, true>(bp, zoom); return;
|
||||
} else {
|
||||
Draw<BlitterMode::ColourRemap, RM_WITH_MARGIN, BT_NONE, true>(bp, zoom); return;
|
||||
Draw<BlitterMode::ColourRemap, ReadMode::WithMargin, BlockType::None, true>(bp, zoom); return;
|
||||
}
|
||||
case BlitterMode::Transparent: Draw<BlitterMode::Transparent, RM_NONE, BT_NONE, true>(bp, zoom); return;
|
||||
case BlitterMode::TransparentRemap: Draw<BlitterMode::TransparentRemap, RM_NONE, BT_NONE, true>(bp, zoom); return;
|
||||
case BlitterMode::CrashRemap: Draw<BlitterMode::CrashRemap, RM_NONE, BT_NONE, true>(bp, zoom); return;
|
||||
case BlitterMode::BlackRemap: Draw<BlitterMode::BlackRemap, RM_NONE, BT_NONE, true>(bp, zoom); return;
|
||||
case BlitterMode::Transparent: Draw<BlitterMode::Transparent, ReadMode::None, BlockType::None, true>(bp, zoom); return;
|
||||
case BlitterMode::TransparentRemap: Draw<BlitterMode::TransparentRemap, ReadMode::None, BlockType::None, true>(bp, zoom); return;
|
||||
case BlitterMode::CrashRemap: Draw<BlitterMode::CrashRemap, ReadMode::None, BlockType::None, true>(bp, zoom); return;
|
||||
case BlitterMode::BlackRemap: Draw<BlitterMode::BlackRemap, ReadMode::None, BlockType::None, true>(bp, zoom); return;
|
||||
}
|
||||
}
|
||||
#endif /* FULL_ANIMATION */
|
||||
|
||||
@@ -68,7 +68,7 @@ protected:
|
||||
*/
|
||||
blitters.insert(Blitters::value_type(this->name, this));
|
||||
} else {
|
||||
Debug(driver, 1, "Not registering blitter {} as it is not usable", name);
|
||||
Debug(Facility::Driver, Severity::Error, "Not registering blitter {} as it is not usable", name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ public:
|
||||
|
||||
GetActiveBlitter() = b->CreateInstance();
|
||||
|
||||
Debug(driver, 1, "Successfully {} blitter '{}'", name.empty() ? "probed" : "loaded", GetCurrentBlitter()->GetName());
|
||||
Debug(Facility::Driver, Severity::Error, "Successfully {} blitter '{}'", name.empty() ? "probed" : "loaded", GetCurrentBlitter()->GetName());
|
||||
return GetCurrentBlitter();
|
||||
}
|
||||
|
||||
|
||||
+10
-10
@@ -110,7 +110,7 @@ public:
|
||||
void DrawWidget(const Rect &r, WidgetID widget) const override
|
||||
{
|
||||
if (widget == WID_BEM_MESSAGE) {
|
||||
DrawStringMultiLine(r.Shrink(WidgetDimensions::scaled.frametext), STR_MISSING_GRAPHICS_ERROR, TextColour::FromString, SA_CENTER);
|
||||
DrawStringMultiLine(r.Shrink(WidgetDimensions::scaled.frametext), STR_MISSING_GRAPHICS_ERROR, TextColour::FromString, {AlignmentH::Centre, AlignmentV::Middle});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,15 +212,15 @@ public:
|
||||
this->Window::Close();
|
||||
}
|
||||
|
||||
void OnInit() override
|
||||
{
|
||||
this->button_size = maxdim(GetStringBoundingBox(STR_MISSING_GRAPHICS_YES_DOWNLOAD), GetStringBoundingBox(STR_MISSING_GRAPHICS_NO_QUIT));
|
||||
this->button_size.width += WidgetDimensions::scaled.frametext.Horizontal();
|
||||
this->button_size.height += WidgetDimensions::scaled.frametext.Vertical();
|
||||
}
|
||||
|
||||
void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
|
||||
{
|
||||
/* We cache the button size. This is safe as no reinit can happen here. */
|
||||
if (this->button_size.width == 0) {
|
||||
this->button_size = maxdim(GetStringBoundingBox(STR_MISSING_GRAPHICS_YES_DOWNLOAD), GetStringBoundingBox(STR_MISSING_GRAPHICS_NO_QUIT));
|
||||
this->button_size.width += WidgetDimensions::scaled.frametext.Horizontal();
|
||||
this->button_size.height += WidgetDimensions::scaled.frametext.Vertical();
|
||||
}
|
||||
|
||||
switch (widget) {
|
||||
case WID_BAFD_QUESTION:
|
||||
/* The question is twice as wide as the buttons, and determine the height based on the width. */
|
||||
@@ -239,7 +239,7 @@ public:
|
||||
{
|
||||
if (widget != WID_BAFD_QUESTION) return;
|
||||
|
||||
DrawStringMultiLine(r.Shrink(WidgetDimensions::scaled.frametext), STR_MISSING_GRAPHICS_SET_MESSAGE, TextColour::FromString, SA_CENTER);
|
||||
DrawStringMultiLine(r.Shrink(WidgetDimensions::scaled.frametext), STR_MISSING_GRAPHICS_SET_MESSAGE, TextColour::FromString, {AlignmentH::Centre, AlignmentV::Middle});
|
||||
}
|
||||
|
||||
void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
|
||||
@@ -381,7 +381,7 @@ bool HandleBootstrap()
|
||||
/* Initialise the font cache. */
|
||||
InitializeUnicodeGlyphMap();
|
||||
/* Next "force" finding a suitable non-sprite font as the local font is missing. */
|
||||
CheckForMissingGlyphs();
|
||||
CheckForMissingGlyphs(FontSize::Normal);
|
||||
|
||||
/* Initialise the palette. The biggest step is 'faking' some recolour sprites.
|
||||
* This way the mauve and gray colours work and we can show the user interface. */
|
||||
|
||||
+4
-3
@@ -43,10 +43,11 @@ struct BridgeSpec {
|
||||
PaletteID pal; ///< the palette which is used in the GUI
|
||||
StringID material; ///< the string that contains the bridge description
|
||||
StringID transport_name[2]; ///< description of the bridge, when built for road or rail
|
||||
std::vector<std::vector<PalSpriteID>> sprite_table; ///< table of sprites for drawing the bridge
|
||||
uint8_t flags; ///< bit 0 set: disable drawing of far pillars.
|
||||
ControlFlags ctrl_flags{}; ///< control flags
|
||||
BridgeMiddlePillarFlags pillar_flags{}; ///< bridge pillar flags.
|
||||
uint8_t flags = 0; ///< bit 0 set: disable drawing of far pillars.
|
||||
|
||||
ControlFlags ctrl_flags{}; ///< control flags, NewGRF-only
|
||||
std::vector<std::vector<PalSpriteID>> sprite_table{}; ///< table of sprites for drawing the bridge, NewGRF-only
|
||||
};
|
||||
|
||||
extern BridgeSpec _bridge[MAX_BRIDGES];
|
||||
|
||||
+1
-1
@@ -250,7 +250,7 @@ public:
|
||||
auto [first, last] = this->vscroll->GetVisibleRangeIterators(this->bridges);
|
||||
for (auto it = first; it != last; ++it) {
|
||||
const BridgeSpec *b = it->spec;
|
||||
DrawSpriteIgnorePadding(b->sprite, b->pal, tr.WithWidth(this->icon_width, rtl), SA_HOR_CENTER | SA_BOTTOM);
|
||||
DrawSpriteIgnorePadding(b->sprite, b->pal, tr.WithWidth(this->icon_width, rtl), {AlignmentH::Centre, AlignmentV::Bottom});
|
||||
DrawStringMultiLineWithClipping(tr.Indent(this->icon_width + WidgetDimensions::scaled.hsep_normal, rtl), GetBridgeSelectString(*it));
|
||||
tr = tr.Translate(0, this->resize.step_height);
|
||||
}
|
||||
|
||||
+31
-29
@@ -264,11 +264,8 @@ static bool EnginePowerVsRunningCostSorter(const GUIEngineListItem &a, const GUI
|
||||
/** Determines order of train engines by capacity. @copydoc GUIList::Sorter */
|
||||
static bool TrainEngineCapacitySorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
|
||||
{
|
||||
const RailVehicleInfo *rvi_a = RailVehInfo(a.engine_id);
|
||||
const RailVehicleInfo *rvi_b = RailVehInfo(b.engine_id);
|
||||
|
||||
int va = GetTotalCapacityOfArticulatedParts(a.engine_id) * (rvi_a->railveh_type == RailVehicleType::Multihead ? 2 : 1);
|
||||
int vb = GetTotalCapacityOfArticulatedParts(b.engine_id) * (rvi_b->railveh_type == RailVehicleType::Multihead ? 2 : 1);
|
||||
int va = GetTotalCapacityOfArticulatedParts(a.engine_id);
|
||||
int vb = GetTotalCapacityOfArticulatedParts(b.engine_id);
|
||||
int r = va - vb;
|
||||
|
||||
/* Use EngineID to sort instead since we want consistent sorting */
|
||||
@@ -962,7 +959,7 @@ void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_li
|
||||
const int offset = (rtl ? -circle_width : circle_width) / 2;
|
||||
const int level_width = rtl ? -WidgetDimensions::scaled.hsep_indent : WidgetDimensions::scaled.hsep_indent;
|
||||
|
||||
for (auto it = first; it != last; ++it) {
|
||||
for (auto it = first; it != last; ++it, ir = ir.Translate(0, step_size)) {
|
||||
const auto &item = *it;
|
||||
const Engine *e = Engine::Get(item.engine_id);
|
||||
|
||||
@@ -971,6 +968,13 @@ void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_li
|
||||
bool is_folded = item.flags.Test(EngineDisplayFlag::IsFolded);
|
||||
bool shaded = item.flags.Test(EngineDisplayFlag::Shaded);
|
||||
|
||||
/* Set up clipping area for the row, keeping coordinates relative to the window. */
|
||||
DrawPixelInfo tmp_dpi;
|
||||
if (!FillDrawPixelInfo(&tmp_dpi, ir)) continue;
|
||||
tmp_dpi.left += ir.left;
|
||||
tmp_dpi.top += ir.top;
|
||||
AutoRestoreBackup dpi_backup(_cur_dpi, &tmp_dpi);
|
||||
|
||||
Rect textr = ir.Shrink(WidgetDimensions::scaled.matrix);
|
||||
Rect tr = ir.Indent(indent, rtl);
|
||||
|
||||
@@ -989,7 +993,7 @@ void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_li
|
||||
|
||||
if (has_variants) {
|
||||
Rect fr = tr.WithWidth(circle_width, rtl);
|
||||
DrawSpriteIgnorePadding(is_folded ? SPR_CIRCLE_FOLDED : SPR_CIRCLE_UNFOLDED, PAL_NONE, fr.WithY(textr), SA_CENTER);
|
||||
DrawSpriteIgnorePadding(is_folded ? SPR_CIRCLE_FOLDED : SPR_CIRCLE_UNFOLDED, PAL_NONE, fr.WithY(textr), {AlignmentH::Centre, AlignmentV::Middle});
|
||||
}
|
||||
|
||||
tr = tr.Indent(circle_width + WidgetDimensions::scaled.hsep_normal, rtl);
|
||||
@@ -1023,10 +1027,10 @@ void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_li
|
||||
Rect cr = tr.WithWidth(count_width, !rtl);
|
||||
tr = tr.Indent(count_width + WidgetDimensions::scaled.hsep_normal, !rtl);
|
||||
|
||||
DrawString(cr.left, cr.right, textr.top + small_text_y_offset, GetString(STR_JUST_COMMA, num_engines), TextColour::Black, SA_RIGHT | SA_FORCE, false, FontSize::Small);
|
||||
DrawString(cr.left, cr.right, textr.top + small_text_y_offset, GetString(STR_JUST_COMMA, num_engines), TextColour::Black, AlignmentH::ForceRight, false, FontSize::Small);
|
||||
|
||||
if (EngineHasReplacementForCompany(Company::Get(_local_company), item.engine_id, selected_group)) {
|
||||
DrawSpriteIgnorePadding(SPR_GROUP_REPLACE_ACTIVE, num_engines == 0 ? PALETTE_CRASH : PAL_NONE, rr, SA_CENTER);
|
||||
DrawSpriteIgnorePadding(SPR_GROUP_REPLACE_ACTIVE, num_engines == 0 ? PALETTE_CRASH : PAL_NONE, rr, {AlignmentH::Centre, AlignmentV::Middle});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1043,24 +1047,24 @@ void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_li
|
||||
/* Draw the value of the currently selected sort property to the right (or left in RTL), if applicable */
|
||||
std::string sort_prop_detail;
|
||||
|
||||
switch (GetEngineSortNames(type)[sort_criteria]) {
|
||||
case STR_SORT_BY_ENGINE_ID:
|
||||
switch (GetEngineSortNames(type)[sort_criteria].base()) {
|
||||
case STR_SORT_BY_ENGINE_ID.base():
|
||||
/* No extra interesting info to show in this case */
|
||||
break;
|
||||
case STR_SORT_BY_COST:
|
||||
case STR_SORT_BY_COST.base():
|
||||
sort_prop_detail = GetString(STR_PURCHASE_SORT_DETAILS_COST, e->GetCost());
|
||||
break;
|
||||
case STR_SORT_BY_MAX_SPEED:
|
||||
case STR_SORT_BY_MAX_SPEED.base():
|
||||
if (int max_speed = e->GetDisplayMaxSpeed(); max_speed != 0) {
|
||||
sort_prop_detail = GetString(STR_PURCHASE_SORT_DETAILS_SPEED, PackVelocity(max_speed, Engine::Get(item.engine_id)->type));
|
||||
}
|
||||
break;
|
||||
case STR_SORT_BY_POWER:
|
||||
case STR_SORT_BY_POWER.base():
|
||||
if (int power = e->GetPower(); power != 0) {
|
||||
sort_prop_detail = GetString(STR_PURCHASE_SORT_DETAILS_POWER, power);
|
||||
}
|
||||
break;
|
||||
case STR_SORT_BY_TRACTIVE_EFFORT:
|
||||
case STR_SORT_BY_TRACTIVE_EFFORT.base():
|
||||
/* Allow trucks, and allow trains that are not wagons */
|
||||
if (type == VehicleType::Road || (type == VehicleType::Train && e->VehInfo<RailVehicleInfo>().railveh_type != RailVehicleType::Wagon)) {
|
||||
auto max_te = e->GetDisplayMaxTractiveEffort();
|
||||
@@ -1069,35 +1073,35 @@ void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_li
|
||||
}
|
||||
}
|
||||
break;
|
||||
case STR_SORT_BY_INTRO_DATE: {
|
||||
case STR_SORT_BY_INTRO_DATE.base(): {
|
||||
TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(e->intro_date);
|
||||
sort_prop_detail = GetString(STR_PURCHASE_SORT_DETAILS_INTRO_DATE, ymd.year);
|
||||
}
|
||||
break;
|
||||
case STR_SORT_BY_NAME:
|
||||
case STR_SORT_BY_NAME.base():
|
||||
/* No extra interesting info to show in this case */
|
||||
break;
|
||||
case STR_SORT_BY_RUNNING_COST:
|
||||
case STR_SORT_BY_RUNNING_COST.base():
|
||||
if (int running_cost = e->GetRunningCost(); running_cost != 0) {
|
||||
sort_prop_detail = GetString(TimerGameEconomy::UsingWallclockUnits() ? STR_PURCHASE_SORT_DETAILS_RUNNINGCOST_PERIOD : STR_PURCHASE_SORT_DETAILS_RUNNINGCOST_YEAR, running_cost);
|
||||
}
|
||||
break;
|
||||
case STR_SORT_BY_POWER_VS_RUNNING_COST:
|
||||
case STR_SORT_BY_POWER_VS_RUNNING_COST.base():
|
||||
/* NOTE: No point showing the actual values of power/running cost, because they are affected by cost factors, which make the math off */
|
||||
if (Money rc = e->GetRunningCost(); rc != 0) {
|
||||
sort_prop_detail = GetString(STR_PURCHASE_SORT_DETAILS_POWER_VS_RUNNING_COST, 100 * e->GetPower() / rc, /* digits for DECIMAL */ 2);
|
||||
}
|
||||
break;
|
||||
case STR_SORT_BY_RELIABILITY:
|
||||
case STR_SORT_BY_RELIABILITY.base():
|
||||
if (auto isWagon = e->type == VehicleType::Train && e->VehInfo<RailVehicleInfo>().railveh_type == RailVehicleType::Wagon; !isWagon) {
|
||||
sort_prop_detail = GetString(STR_PURCHASE_SORT_DETAILS_RELIABILITY, ToPercent16(e->reliability));
|
||||
}
|
||||
break;
|
||||
case STR_SORT_BY_CARGO_CAPACITY: {
|
||||
case STR_SORT_BY_CARGO_CAPACITY.base(): {
|
||||
uint total_capacity;
|
||||
switch (type) {
|
||||
case VehicleType::Train:
|
||||
total_capacity = GetTotalCapacityOfArticulatedParts(item.engine_id) * (e->VehInfo<RailVehicleInfo>().railveh_type == RailVehicleType::Multihead ? 2 : 1);
|
||||
total_capacity = GetTotalCapacityOfArticulatedParts(item.engine_id);
|
||||
break;
|
||||
case VehicleType::Road:
|
||||
total_capacity = GetTotalCapacityOfArticulatedParts(item.engine_id);
|
||||
@@ -1120,7 +1124,7 @@ void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_li
|
||||
}
|
||||
}
|
||||
break;
|
||||
case STR_SORT_BY_RANGE:
|
||||
case STR_SORT_BY_RANGE.base():
|
||||
if (e->type == VehicleType::Aircraft) {
|
||||
if (uint16_t range = e->GetRange(); range != 0) {
|
||||
sort_prop_detail = GetString(STR_PURCHASE_SORT_DETAILS_AIRCRAFT_RANGE, range);
|
||||
@@ -1133,7 +1137,7 @@ void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_li
|
||||
|
||||
int sort_detail_width = 0;
|
||||
if (!sort_prop_detail.empty()) {
|
||||
DrawString(tr.left, tr.right, textr.top + normal_text_y_offset, sort_prop_detail, tc, SA_RIGHT, false, FontSize::Small);
|
||||
DrawString(tr.left, tr.right, textr.top + normal_text_y_offset, sort_prop_detail, tc, AlignmentH::End, false, FontSize::Small);
|
||||
|
||||
/* If we have sort detail to show, also measure its width so that we can adjust the
|
||||
* main name drawing rectangle to not overlap. */
|
||||
@@ -1146,8 +1150,6 @@ void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_li
|
||||
|
||||
/* The left/right bounds are adjusted to not overlap with the sort detail that is on the left/right depending on the RTL setting. */
|
||||
DrawString(tr.left + (rtl ? sort_detail_width : 0), tr.right - (rtl ? 0 : sort_detail_width), textr.top + normal_text_y_offset, name, tc);
|
||||
|
||||
ir = ir.Translate(0, step_size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1375,7 +1377,7 @@ struct BuildVehicleWindow : Window {
|
||||
|
||||
if (!this->listview_mode) {
|
||||
/* Query for cost and refitted capacity */
|
||||
auto [ret, veh_id, refit_capacity, refit_mail, cargo_capacities] = Command<Commands::BuildVehicle>::Do(DoCommandFlag::QueryCost, TileIndex(this->window_number), this->sel_engine, true, cargo, INVALID_CLIENT_ID);
|
||||
auto [ret, veh_id, refit_capacity, refit_mail, cargo_capacities] = Command<Commands::BuildVehicle>::Do(DoCommandFlag::QueryCost, TileIndex(this->window_number), this->sel_engine, true, cargo, ClientID::Invalid);
|
||||
if (ret.Succeeded()) {
|
||||
this->te.cost = ret.GetCost() - e->GetCost();
|
||||
this->te.capacity = refit_capacity;
|
||||
@@ -1697,9 +1699,9 @@ struct BuildVehicleWindow : Window {
|
||||
CargoType cargo = this->cargo_filter_criteria;
|
||||
if (cargo == CargoFilterCriteria::CF_ANY || cargo == CargoFilterCriteria::CF_ENGINES || cargo == CargoFilterCriteria::CF_NONE) cargo = INVALID_CARGO;
|
||||
if (this->vehicle_type == VehicleType::Train && RailVehInfo(sel_eng)->railveh_type == RailVehicleType::Wagon) {
|
||||
Command<Commands::BuildVehicle>::Post(GetCmdBuildVehMsg(this->vehicle_type), CcBuildWagon, TileIndex(this->window_number), sel_eng, true, cargo, INVALID_CLIENT_ID);
|
||||
Command<Commands::BuildVehicle>::Post(GetCmdBuildVehMsg(this->vehicle_type), CcBuildWagon, TileIndex(this->window_number), sel_eng, true, cargo, ClientID::Invalid);
|
||||
} else {
|
||||
Command<Commands::BuildVehicle>::Post(GetCmdBuildVehMsg(this->vehicle_type), CcBuildPrimaryVehicle, TileIndex(this->window_number), sel_eng, true, cargo, INVALID_CLIENT_ID);
|
||||
Command<Commands::BuildVehicle>::Post(GetCmdBuildVehMsg(this->vehicle_type), CcBuildPrimaryVehicle, TileIndex(this->window_number), sel_eng, true, cargo, ClientID::Invalid);
|
||||
}
|
||||
|
||||
/* Update last used variant in hierarchy and refresh if necessary. */
|
||||
|
||||
+15
-15
@@ -37,7 +37,7 @@ void CheckCaches()
|
||||
{
|
||||
/* Return here so it is easy to add checks that are run
|
||||
* always to aid testing of caches. */
|
||||
if (_debug_desync_level <= 1) return;
|
||||
if (!IsVisibleSeverity(Facility::Desync, Severity::Warning)) return;
|
||||
|
||||
/* Check the town caches. */
|
||||
std::vector<TownCache> old_town_caches;
|
||||
@@ -51,7 +51,7 @@ void CheckCaches()
|
||||
uint i = 0;
|
||||
for (Town *t : Town::Iterate()) {
|
||||
if (old_town_caches[i] != t->cache) {
|
||||
Debug(desync, 2, "warning: town cache mismatch: town {}", t->index);
|
||||
Debug(Facility::Desync, Severity::Warning, "warning: town cache mismatch: town {}", t->index);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
@@ -65,7 +65,7 @@ void CheckCaches()
|
||||
i = 0;
|
||||
for (const Company *c : Company::Iterate()) {
|
||||
if (old_infrastructure[i] != c->infrastructure) {
|
||||
Debug(desync, 2, "warning: infrastructure cache mismatch: company {}", c->index);
|
||||
Debug(Facility::Desync, Severity::Warning, "warning: infrastructure cache mismatch: company {}", c->index);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
@@ -115,23 +115,23 @@ void CheckCaches()
|
||||
for (const Vehicle *u = v; u != nullptr; u = u->Next()) {
|
||||
FillNewGRFVehicleCache(u);
|
||||
if (grf_cache[length] != u->grf_cache) {
|
||||
Debug(desync, 2, "warning: newgrf cache mismatch: type {}, vehicle {}, company {}, unit number {}, wagon {}", v->type, v->index, v->owner, v->unitnumber, length);
|
||||
Debug(Facility::Desync, Severity::Warning, "warning: newgrf cache mismatch: type {}, vehicle {}, company {}, unit number {}, wagon {}", v->type, v->index, v->owner, v->unitnumber, length);
|
||||
}
|
||||
if (veh_cache[length] != u->vcache) {
|
||||
Debug(desync, 2, "warning: vehicle cache mismatch: type {}, vehicle {}, company {}, unit number {}, wagon {}", v->type, v->index, v->owner, v->unitnumber, length);
|
||||
Debug(Facility::Desync, Severity::Warning, "warning: vehicle cache mismatch: type {}, vehicle {}, company {}, unit number {}, wagon {}", v->type, v->index, v->owner, v->unitnumber, length);
|
||||
}
|
||||
switch (u->type) {
|
||||
case VehicleType::Train:
|
||||
if (gro_cache[length] != Train::From(u)->gcache) {
|
||||
Debug(desync, 2, "warning: train ground vehicle cache mismatch: vehicle {}, company {}, unit number {}, wagon {}", v->index, v->owner, v->unitnumber, length);
|
||||
Debug(Facility::Desync, Severity::Warning, "warning: train ground vehicle cache mismatch: vehicle {}, company {}, unit number {}, wagon {}", v->index, v->owner, v->unitnumber, length);
|
||||
}
|
||||
if (tra_cache[length] != Train::From(u)->tcache) {
|
||||
Debug(desync, 2, "warning: train cache mismatch: vehicle {}, company {}, unit number {}, wagon {}", v->index, v->owner, v->unitnumber, length);
|
||||
Debug(Facility::Desync, Severity::Warning, "warning: train cache mismatch: vehicle {}, company {}, unit number {}, wagon {}", v->index, v->owner, v->unitnumber, length);
|
||||
}
|
||||
break;
|
||||
case VehicleType::Road:
|
||||
if (gro_cache[length] != RoadVehicle::From(u)->gcache) {
|
||||
Debug(desync, 2, "warning: road vehicle ground vehicle cache mismatch: vehicle {}, company {}, unit number {}, wagon {}", v->index, v->owner, v->unitnumber, length);
|
||||
Debug(Facility::Desync, Severity::Warning, "warning: road vehicle ground vehicle cache mismatch: vehicle {}, company {}, unit number {}, wagon {}", v->index, v->owner, v->unitnumber, length);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -188,11 +188,11 @@ void CheckCaches()
|
||||
}
|
||||
UpdateStationDockingTiles(st);
|
||||
if (ta.tile != st->docking_station.tile || ta.w != st->docking_station.w || ta.h != st->docking_station.h) {
|
||||
Debug(desync, 2, "warning: station docking mismatch: station {}, company {}", st->index, st->owner);
|
||||
Debug(Facility::Desync, Severity::Warning, "warning: station docking mismatch: station {}, company {}", st->index, st->owner);
|
||||
}
|
||||
for (TileIndex tile : ta) {
|
||||
if (docking_tiles[tile] != IsDockingTile(tile)) {
|
||||
Debug(desync, 2, "warning: docking tile mismatch: tile {}", tile);
|
||||
Debug(Facility::Desync, Severity::Warning, "warning: docking tile mismatch: tile {}", tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -203,7 +203,7 @@ void CheckCaches()
|
||||
i = 0;
|
||||
for (Station *st : Station::Iterate()) {
|
||||
if (st->industries_near != old_station_industries_near[i]) {
|
||||
Debug(desync, 2, "warning: station industries near mismatch: station {}", st->index);
|
||||
Debug(Facility::Desync, Severity::Warning, "warning: station industries near mismatch: station {}", st->index);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
@@ -212,14 +212,14 @@ void CheckCaches()
|
||||
i = 0;
|
||||
for (Town *t : Town::Iterate()) {
|
||||
if (t->stations_near != old_town_stations_near[i]) {
|
||||
Debug(desync, 2, "warning: town stations near mismatch: town {}", t->index);
|
||||
Debug(Facility::Desync, Severity::Warning, "warning: town stations near mismatch: town {}", t->index);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
i = 0;
|
||||
for (Industry *ind : Industry::Iterate()) {
|
||||
if (ind->stations_near != old_industry_stations_near[i]) {
|
||||
Debug(desync, 2, "warning: industry stations near mismatch: industry {}", ind->index);
|
||||
Debug(Facility::Desync, Severity::Warning, "warning: industry stations near mismatch: industry {}", ind->index);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
@@ -230,13 +230,13 @@ void CheckCaches()
|
||||
|
||||
/* Check that the last vehicle is actually last. */
|
||||
if (v->Last()->Next() != nullptr) {
|
||||
Debug(desync, 2, "warning: vehicle cache mismatch, last vehicle must not have a next vehicle: type {}, vehicle {}, company {}, unit number {}, invalid 'Last()'", v->type, v->index, v->owner, v->unitnumber);
|
||||
Debug(Facility::Desync, Severity::Warning, "warning: vehicle cache mismatch, last vehicle must not have a next vehicle: type {}, vehicle {}, company {}, unit number {}, invalid 'Last()'", v->type, v->index, v->owner, v->unitnumber);
|
||||
}
|
||||
|
||||
/* Ensure that all vehicles in the chain have the same last vehicle. */
|
||||
for (Vehicle *u = v; u != nullptr; u = u->Next()) {
|
||||
if (u->Last() != v->Last()) {
|
||||
Debug(desync, 2, "warning: vehicle cache mismatch, all vehicles in chain must have same last vehicle: type {}, vehicle {}, company {}, unit number {}, invalid 'Last()'", v->type, v->index, v->owner, v->unitnumber);
|
||||
Debug(Facility::Desync, Severity::Warning, "warning: vehicle cache mismatch, all vehicles in chain must have same last vehicle: type {}, vehicle {}, company {}, unit number {}, invalid 'Last()'", v->type, v->index, v->owner, v->unitnumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+34
-34
@@ -10,11 +10,11 @@
|
||||
#ifndef CARGO_TYPE_H
|
||||
#define CARGO_TYPE_H
|
||||
|
||||
#include "core/strong_typedef_type.hpp"
|
||||
#include "core/label_type.hpp"
|
||||
#include "core/enum_type.hpp"
|
||||
|
||||
/** Globally unique label of a cargo type. */
|
||||
using CargoLabel = StrongType::Typedef<uint32_t, struct CargoLabelTag, StrongType::Compare>;
|
||||
using CargoLabel = Label<struct CargoLabelTag>;
|
||||
|
||||
/**
|
||||
* Cargo slots to indicate a cargo type within a game.
|
||||
@@ -28,48 +28,48 @@ DECLARE_INCREMENT_DECREMENT_OPERATORS(CargoType)
|
||||
*/
|
||||
|
||||
/* Temperate */
|
||||
static constexpr CargoLabel CT_PASSENGERS{'PASS'};
|
||||
static constexpr CargoLabel CT_COAL{'COAL'};
|
||||
static constexpr CargoLabel CT_MAIL{'MAIL'};
|
||||
static constexpr CargoLabel CT_OIL{'OIL_'};
|
||||
static constexpr CargoLabel CT_LIVESTOCK{'LVST'};
|
||||
static constexpr CargoLabel CT_GOODS{'GOOD'};
|
||||
static constexpr CargoLabel CT_GRAIN{'GRAI'};
|
||||
static constexpr CargoLabel CT_WOOD{'WOOD'};
|
||||
static constexpr CargoLabel CT_IRON_ORE{'IORE'};
|
||||
static constexpr CargoLabel CT_STEEL{'STEL'};
|
||||
static constexpr CargoLabel CT_VALUABLES{'VALU'};
|
||||
static constexpr CargoLabel CT_PASSENGERS{"PASS"};
|
||||
static constexpr CargoLabel CT_COAL{"COAL"};
|
||||
static constexpr CargoLabel CT_MAIL{"MAIL"};
|
||||
static constexpr CargoLabel CT_OIL{"OIL_"};
|
||||
static constexpr CargoLabel CT_LIVESTOCK{"LVST"};
|
||||
static constexpr CargoLabel CT_GOODS{"GOOD"};
|
||||
static constexpr CargoLabel CT_GRAIN{"GRAI"};
|
||||
static constexpr CargoLabel CT_WOOD{"WOOD"};
|
||||
static constexpr CargoLabel CT_IRON_ORE{"IORE"};
|
||||
static constexpr CargoLabel CT_STEEL{"STEL"};
|
||||
static constexpr CargoLabel CT_VALUABLES{"VALU"};
|
||||
|
||||
/* Arctic */
|
||||
static constexpr CargoLabel CT_WHEAT{'WHEA'};
|
||||
static constexpr CargoLabel CT_PAPER{'PAPR'};
|
||||
static constexpr CargoLabel CT_GOLD{'GOLD'};
|
||||
static constexpr CargoLabel CT_FOOD{'FOOD'};
|
||||
static constexpr CargoLabel CT_WHEAT{"WHEA"};
|
||||
static constexpr CargoLabel CT_PAPER{"PAPR"};
|
||||
static constexpr CargoLabel CT_GOLD{"GOLD"};
|
||||
static constexpr CargoLabel CT_FOOD{"FOOD"};
|
||||
|
||||
/* Tropic */
|
||||
static constexpr CargoLabel CT_RUBBER{'RUBR'};
|
||||
static constexpr CargoLabel CT_FRUIT{'FRUT'};
|
||||
static constexpr CargoLabel CT_MAIZE{'MAIZ'};
|
||||
static constexpr CargoLabel CT_COPPER_ORE{'CORE'};
|
||||
static constexpr CargoLabel CT_WATER{'WATR'};
|
||||
static constexpr CargoLabel CT_DIAMONDS{'DIAM'};
|
||||
static constexpr CargoLabel CT_RUBBER{"RUBR"};
|
||||
static constexpr CargoLabel CT_FRUIT{"FRUT"};
|
||||
static constexpr CargoLabel CT_MAIZE{"MAIZ"};
|
||||
static constexpr CargoLabel CT_COPPER_ORE{"CORE"};
|
||||
static constexpr CargoLabel CT_WATER{"WATR"};
|
||||
static constexpr CargoLabel CT_DIAMONDS{"DIAM"};
|
||||
|
||||
/* Toyland */
|
||||
static constexpr CargoLabel CT_SUGAR{'SUGR'};
|
||||
static constexpr CargoLabel CT_TOYS{'TOYS'};
|
||||
static constexpr CargoLabel CT_BATTERIES{'BATT'};
|
||||
static constexpr CargoLabel CT_CANDY{'SWET'};
|
||||
static constexpr CargoLabel CT_TOFFEE{'TOFF'};
|
||||
static constexpr CargoLabel CT_COLA{'COLA'};
|
||||
static constexpr CargoLabel CT_COTTON_CANDY{'CTCD'};
|
||||
static constexpr CargoLabel CT_BUBBLES{'BUBL'};
|
||||
static constexpr CargoLabel CT_PLASTIC{'PLST'};
|
||||
static constexpr CargoLabel CT_FIZZY_DRINKS{'FZDR'};
|
||||
static constexpr CargoLabel CT_SUGAR{"SUGR"};
|
||||
static constexpr CargoLabel CT_TOYS{"TOYS"};
|
||||
static constexpr CargoLabel CT_BATTERIES{"BATT"};
|
||||
static constexpr CargoLabel CT_CANDY{"SWET"};
|
||||
static constexpr CargoLabel CT_TOFFEE{"TOFF"};
|
||||
static constexpr CargoLabel CT_COLA{"COLA"};
|
||||
static constexpr CargoLabel CT_COTTON_CANDY{"CTCD"};
|
||||
static constexpr CargoLabel CT_BUBBLES{"BUBL"};
|
||||
static constexpr CargoLabel CT_PLASTIC{"PLST"};
|
||||
static constexpr CargoLabel CT_FIZZY_DRINKS{"FZDR"};
|
||||
|
||||
/** Dummy label for engines that carry no cargo; they actually carry 0 passengers. */
|
||||
static constexpr CargoLabel CT_NONE = CT_PASSENGERS;
|
||||
|
||||
static constexpr CargoLabel CT_INVALID{UINT32_MAX}; ///< Invalid cargo type.
|
||||
static constexpr CargoLabel CT_INVALID{"\xFF\xFF\xFF\xFF"}; ///< Invalid cargo type.
|
||||
|
||||
static constexpr CargoType NUM_ORIGINAL_CARGO{12}; ///< Original number of cargo types.
|
||||
static constexpr CargoType NUM_CARGO{64}; ///< Maximum number of cargo types in a game.
|
||||
|
||||
+8
-1
@@ -93,7 +93,14 @@ template <>
|
||||
bool CargoRemoval<VehicleCargoList>::operator()(CargoPacket *cp)
|
||||
{
|
||||
uint remove = this->Preprocess(cp);
|
||||
this->source->RemoveFromMeta(cp, VehicleCargoList::MoveToAction::Keep, remove);
|
||||
|
||||
uint remaining = remove;
|
||||
for (VehicleCargoList::MoveToAction action : {VehicleCargoList::MoveToAction::Keep, VehicleCargoList::MoveToAction::Transfer, VehicleCargoList::MoveToAction::Deliver, VehicleCargoList::MoveToAction::Load}) {
|
||||
remaining -= this->source->TryRemoveFromMeta(cp, action, remaining);
|
||||
if (remaining == 0) break;
|
||||
}
|
||||
assert(remaining == 0);
|
||||
|
||||
return this->Postprocess(cp, remove);
|
||||
}
|
||||
|
||||
|
||||
@@ -373,6 +373,20 @@ void VehicleCargoList::RemoveFromMeta(const CargoPacket *cp, MoveToAction action
|
||||
this->AssertCountConsistency();
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to remove a packet or part of it from the metadata.
|
||||
* @param cp Packet to be removed.
|
||||
* @param action MoveToAction of the packet (for updating the counts).
|
||||
* @param count Amount of cargo to be removed.
|
||||
* @return Amount of cargo removed.
|
||||
*/
|
||||
uint VehicleCargoList::TryRemoveFromMeta(const CargoPacket *cp, MoveToAction action, uint count)
|
||||
{
|
||||
uint remove = std::min(this->action_counts[action], count);
|
||||
if (remove > 0) this->RemoveFromMeta(cp, action, remove);
|
||||
return remove;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a packet to the metadata.
|
||||
* @param cp Packet to be added.
|
||||
|
||||
+2
-1
@@ -18,7 +18,7 @@
|
||||
#include "source_type.h"
|
||||
#include "vehicle_type.h"
|
||||
#include "core/multimap.hpp"
|
||||
#include "saveload/saveload.h"
|
||||
#include "saveload/saveload_type.h"
|
||||
|
||||
/** Unique identifier for a single cargo packet. */
|
||||
using CargoPacketID = PoolID<uint32_t, struct CargoPacketIDTag, 0xFFF000, 0xFFFFFF>;
|
||||
@@ -361,6 +361,7 @@ protected:
|
||||
|
||||
void AddToMeta(const CargoPacket *cp, MoveToAction action);
|
||||
void RemoveFromMeta(const CargoPacket *cp, MoveToAction action, uint count);
|
||||
uint TryRemoveFromMeta(const CargoPacket *cp, MoveToAction action, uint count);
|
||||
|
||||
static MoveToAction ChooseAction(const CargoPacket *cp, StationID cargo_next,
|
||||
StationID current_station, bool accepted, std::span<const StationID> next_station);
|
||||
|
||||
+19
-20
@@ -13,7 +13,6 @@
|
||||
#include "company_base.h"
|
||||
#include "company_func.h"
|
||||
#include "currency_func.h"
|
||||
#include "saveload/saveload.h"
|
||||
#include "vehicle_base.h"
|
||||
#include "textbuf_gui.h"
|
||||
#include "window_gui.h"
|
||||
@@ -192,7 +191,7 @@ typedef int32_t CheckButtonClick(int32_t new_value, int32_t change_direction);
|
||||
|
||||
/** Information of a cheat. */
|
||||
struct CheatEntry {
|
||||
VarType type; ///< type of selector
|
||||
VarMemType type; ///< type of selector
|
||||
StringID str; ///< string with descriptive text
|
||||
void *variable; ///< pointer to the variable
|
||||
bool *been_used; ///< has this cheat been used before?
|
||||
@@ -204,15 +203,15 @@ struct CheatEntry {
|
||||
* Order matches with the values of #CheatNumbers
|
||||
*/
|
||||
static const CheatEntry _cheats_ui[] = {
|
||||
{SLE_INT32, STR_CHEAT_MONEY, &_money_cheat_amount, &_cheats.money.been_used, &ClickMoneyCheat },
|
||||
{SLE_UINT8, STR_CHEAT_CHANGE_COMPANY, &_local_company, &_cheats.switch_company.been_used, &ClickChangeCompanyCheat },
|
||||
{SLE_BOOL, STR_CHEAT_EXTRA_DYNAMITE, &_cheats.magic_bulldozer.value, &_cheats.magic_bulldozer.been_used, nullptr },
|
||||
{SLE_BOOL, STR_CHEAT_CROSSINGTUNNELS, &_cheats.crossing_tunnels.value, &_cheats.crossing_tunnels.been_used, nullptr },
|
||||
{SLE_BOOL, STR_CHEAT_NO_JETCRASH, &_cheats.no_jetcrash.value, &_cheats.no_jetcrash.been_used, nullptr },
|
||||
{SLE_BOOL, STR_CHEAT_SETUP_PROD, &_cheats.setup_prod.value, &_cheats.setup_prod.been_used, &ClickSetProdCheat },
|
||||
{SLE_BOOL, STR_CHEAT_STATION_RATING, &_cheats.station_rating.value, &_cheats.station_rating.been_used, nullptr },
|
||||
{SLE_UINT8, STR_CHEAT_EDIT_MAX_HL, &_settings_game.construction.map_height_limit, &_cheats.edit_max_hl.been_used, &ClickChangeMaxHlCheat },
|
||||
{SLE_INT32, STR_CHEAT_CHANGE_DATE, &TimerGameCalendar::year, &_cheats.change_date.been_used, &ClickChangeDateCheat },
|
||||
{ VarMemType::I32, STR_CHEAT_MONEY, &_money_cheat_amount, &_cheats.money.been_used, &ClickMoneyCheat },
|
||||
{ VarMemType::U8, STR_CHEAT_CHANGE_COMPANY, &_local_company, &_cheats.switch_company.been_used, &ClickChangeCompanyCheat },
|
||||
{ VarMemType::Bool, STR_CHEAT_EXTRA_DYNAMITE, &_cheats.magic_bulldozer.value, &_cheats.magic_bulldozer.been_used, nullptr },
|
||||
{ VarMemType::Bool, STR_CHEAT_CROSSINGTUNNELS, &_cheats.crossing_tunnels.value, &_cheats.crossing_tunnels.been_used, nullptr },
|
||||
{ VarMemType::Bool, STR_CHEAT_NO_JETCRASH, &_cheats.no_jetcrash.value, &_cheats.no_jetcrash.been_used, nullptr },
|
||||
{ VarMemType::Bool, STR_CHEAT_SETUP_PROD, &_cheats.setup_prod.value, &_cheats.setup_prod.been_used, &ClickSetProdCheat },
|
||||
{ VarMemType::Bool, STR_CHEAT_STATION_RATING, &_cheats.station_rating.value, &_cheats.station_rating.been_used, nullptr },
|
||||
{ VarMemType::U8, STR_CHEAT_EDIT_MAX_HL, &_settings_game.construction.map_height_limit, &_cheats.edit_max_hl.been_used, &ClickChangeMaxHlCheat },
|
||||
{ VarMemType::I32, STR_CHEAT_CHANGE_DATE, &TimerGameCalendar::year, &_cheats.change_date.been_used, &ClickChangeDateCheat },
|
||||
};
|
||||
|
||||
static_assert(CHT_NUM_CHEATS == lengthof(_cheats_ui));
|
||||
@@ -283,7 +282,7 @@ struct CheatWindow : Window {
|
||||
|
||||
std::string str;
|
||||
switch (ce->type) {
|
||||
case SLE_BOOL: {
|
||||
case VarMemType::Bool: {
|
||||
bool on = (*(bool*)ce->variable);
|
||||
|
||||
DrawBoolButton(button_left, y + button_y_offset, Colours::Yellow, Colours::Grey, on, true);
|
||||
@@ -297,14 +296,14 @@ struct CheatWindow : Window {
|
||||
/* Draw [<][>] boxes for settings of an integer-type */
|
||||
DrawArrowButtons(button_left, y + button_y_offset, Colours::Yellow, clicked - (i * 2), true, true);
|
||||
|
||||
switch (ce->str) {
|
||||
switch (ce->str.base()) {
|
||||
/* Display date for change date cheat */
|
||||
case STR_CHEAT_CHANGE_DATE:
|
||||
case STR_CHEAT_CHANGE_DATE.base():
|
||||
str = GetString(ce->str, TimerGameCalendar::date);
|
||||
break;
|
||||
|
||||
/* Draw coloured flag for change company cheat */
|
||||
case STR_CHEAT_CHANGE_COMPANY: {
|
||||
case STR_CHEAT_CHANGE_COMPANY.base(): {
|
||||
str = GetString(ce->str, val + 1);
|
||||
uint offset = WidgetDimensions::scaled.hsep_indent + GetStringBoundingBox(str).width;
|
||||
DrawCompanyIcon(_local_company, rtl ? text_right - offset - WidgetDimensions::scaled.hsep_indent : text_left + offset, y + icon_y_offset);
|
||||
@@ -380,20 +379,20 @@ struct CheatWindow : Window {
|
||||
uint width = 0;
|
||||
for (const auto &ce : _cheats_ui) {
|
||||
switch (ce.type) {
|
||||
case SLE_BOOL:
|
||||
case VarMemType::Bool:
|
||||
width = std::max(width, GetStringBoundingBox(GetString(ce.str, STR_CONFIG_SETTING_ON)).width);
|
||||
width = std::max(width, GetStringBoundingBox(GetString(ce.str, STR_CONFIG_SETTING_OFF)).width);
|
||||
break;
|
||||
|
||||
default:
|
||||
switch (ce.str) {
|
||||
switch (ce.str.base()) {
|
||||
/* Display date for change date cheat */
|
||||
case STR_CHEAT_CHANGE_DATE:
|
||||
case STR_CHEAT_CHANGE_DATE.base():
|
||||
width = std::max(width, GetStringBoundingBox(GetString(ce.str, TimerGameCalendar::ConvertYMDToDate(CalendarTime::MAX_YEAR, 11, 31))).width);
|
||||
break;
|
||||
|
||||
/* Draw coloured flag for change company cheat */
|
||||
case STR_CHEAT_CHANGE_COMPANY:
|
||||
case STR_CHEAT_CHANGE_COMPANY.base():
|
||||
width = std::max(width, GetStringBoundingBox(GetString(ce.str, MAX_COMPANIES)).width + WidgetDimensions::scaled.hsep_wide);
|
||||
break;
|
||||
|
||||
@@ -466,7 +465,7 @@ struct CheatWindow : Window {
|
||||
*ce->been_used = true;
|
||||
|
||||
switch (ce->type) {
|
||||
case SLE_BOOL:
|
||||
case VarMemType::Bool:
|
||||
value ^= 1;
|
||||
if (ce->proc != nullptr) ce->proc(value, 0);
|
||||
break;
|
||||
|
||||
+130
-37
@@ -48,17 +48,31 @@ static CommandCost ClearTile_Clear(TileIndex tile, DoCommandFlags flags)
|
||||
price.AddCost(_price[clear_price_table[ground]]);
|
||||
}
|
||||
|
||||
if (flags.Test(DoCommandFlag::Execute)) DoClearSquare(tile);
|
||||
if (flags.Test(DoCommandFlag::Execute)) {
|
||||
DoClearSquare(tile);
|
||||
|
||||
/* We might want to clear to rocks instead of dirt/grass. */
|
||||
if (flags.Test(DoCommandFlag::ClearToRocks)) MakeClear(tile, ClearGround::Rocks, 3);
|
||||
}
|
||||
|
||||
return price;
|
||||
}
|
||||
|
||||
void DrawClearLandTile(const TileInfo *ti, uint8_t set)
|
||||
/**
|
||||
* Draw a ClearGround::Grass tile.
|
||||
* @param ti The tile to draw.
|
||||
* @param density The density of the dirt -> grass transition to draw.
|
||||
*/
|
||||
void DrawClearLandTile(const TileInfo *ti, uint8_t density)
|
||||
{
|
||||
DrawGroundSprite(SPR_FLAT_BARE_LAND + SlopeToSpriteOffset(ti->tileh) + set * 19, PAL_NONE);
|
||||
DrawGroundSprite(_clear_land_sprites_grass[density] + SlopeToSpriteOffset(ti->tileh), PAL_NONE);
|
||||
}
|
||||
|
||||
void DrawHillyLandTile(const TileInfo *ti)
|
||||
/**
|
||||
* Draw a ClearGround::Rough tile.
|
||||
* @param ti The tile to draw.
|
||||
*/
|
||||
void DrawRoughLandTile(const TileInfo *ti)
|
||||
{
|
||||
if (ti->tileh != SLOPE_FLAT) {
|
||||
DrawGroundSprite(SPR_FLAT_ROUGH_LAND + SlopeToSpriteOffset(ti->tileh), PAL_NONE);
|
||||
@@ -67,6 +81,10 @@ void DrawHillyLandTile(const TileInfo *ti)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw the fences atop a ClearGround::Fields tile.
|
||||
* @param ti The tile to draw.
|
||||
*/
|
||||
static void DrawClearLandFence(const TileInfo *ti)
|
||||
{
|
||||
/* combine fences into one sprite object */
|
||||
@@ -80,7 +98,7 @@ static void DrawClearLandFence(const TileInfo *ti)
|
||||
if (fence_nw != 0) {
|
||||
bounds.offset.x = 0;
|
||||
bounds.offset.y = -static_cast<int>(TILE_SIZE);
|
||||
bounds.offset.z = GetSlopePixelZInCorner(ti->tileh, CORNER_W);
|
||||
bounds.offset.z = GetSlopePixelZInCorner(ti->tileh, Corner::W);
|
||||
SpriteID sprite = _clear_land_fence_sprites[fence_nw - 1] + _fence_mod_by_tileh_nw[ti->tileh];
|
||||
AddSortableSpriteToDraw(sprite, PAL_NONE, *ti, bounds, false);
|
||||
}
|
||||
@@ -89,7 +107,7 @@ static void DrawClearLandFence(const TileInfo *ti)
|
||||
if (fence_ne != 0) {
|
||||
bounds.offset.x = -static_cast<int>(TILE_SIZE);
|
||||
bounds.offset.y = 0;
|
||||
bounds.offset.z = GetSlopePixelZInCorner(ti->tileh, CORNER_E);
|
||||
bounds.offset.z = GetSlopePixelZInCorner(ti->tileh, Corner::E);
|
||||
SpriteID sprite = _clear_land_fence_sprites[fence_ne - 1] + _fence_mod_by_tileh_ne[ti->tileh];
|
||||
AddSortableSpriteToDraw(sprite, PAL_NONE, *ti, bounds, false);
|
||||
}
|
||||
@@ -100,7 +118,7 @@ static void DrawClearLandFence(const TileInfo *ti)
|
||||
if (fence_sw != 0 || fence_se != 0) {
|
||||
bounds.offset.x = 0;
|
||||
bounds.offset.y = 0;
|
||||
bounds.offset.z = GetSlopePixelZInCorner(ti->tileh, CORNER_S);
|
||||
bounds.offset.z = GetSlopePixelZInCorner(ti->tileh, Corner::S);
|
||||
|
||||
if (fence_sw != 0) {
|
||||
SpriteID sprite = _clear_land_fence_sprites[fence_sw - 1] + _fence_mod_by_tileh_sw[ti->tileh];
|
||||
@@ -123,9 +141,7 @@ static void DrawTile_Clear(TileInfo *ti)
|
||||
uint8_t density = GetClearDensity(ti->tile);
|
||||
DrawGroundSprite(_clear_land_sprites_snow_desert[density] + SlopeToSpriteOffset(ti->tileh), PAL_NONE);
|
||||
if (GetClearGround(ti->tile) == ClearGround::Rocks) {
|
||||
/* There 4 levels of snowy overlay rocks, each with 19 sprites. */
|
||||
++density;
|
||||
DrawGroundSprite(SPR_OVERLAY_ROCKS_BASE + (density * 19) + SlopeToSpriteOffset(ti->tileh), PAL_NONE);
|
||||
DrawGroundSprite(_clear_land_sprites_snowy_rocks[density] + SlopeToSpriteOffset(ti->tileh), PAL_NONE);
|
||||
}
|
||||
|
||||
DrawBridgeMiddle(ti, {});
|
||||
@@ -138,7 +154,7 @@ static void DrawTile_Clear(TileInfo *ti)
|
||||
break;
|
||||
|
||||
case ClearGround::Rough:
|
||||
DrawHillyLandTile(ti);
|
||||
DrawRoughLandTile(ti);
|
||||
break;
|
||||
|
||||
case ClearGround::Rocks:
|
||||
@@ -328,44 +344,121 @@ static void TileLoop_Clear(TileIndex tile)
|
||||
MarkTileDirtyByTile(tile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if a tile may have rocks on.
|
||||
* @param tile The tile index.
|
||||
* @param allow_water Whether to consider plain water tiles.
|
||||
* @return true if the tile may have rocks.
|
||||
*/
|
||||
static bool TileMayHaveRocks(TileIndex tile, bool allow_water)
|
||||
{
|
||||
if (!IsValidTile(tile)) return false;
|
||||
switch (GetTileType(tile)) {
|
||||
case TileType::Clear: return true;
|
||||
case TileType::Water: return IsCoast(tile) || (allow_water && (IsSea(tile) || IsRiver(tile)));
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a tile that may have rocks on have rocks on.
|
||||
* @param tile The tile index.
|
||||
*/
|
||||
static void TileMakeRocks(TileIndex tile)
|
||||
{
|
||||
switch (GetTileType(tile)) {
|
||||
case TileType::Clear:
|
||||
SetClearGroundDensity(tile, ClearGround::Rocks, 3);
|
||||
break;
|
||||
|
||||
case TileType::Water:
|
||||
/* Rocks can jump over but not replace rivers. */
|
||||
if (IsRiver(tile)) return;
|
||||
SetWaterTileType(tile, IsCoast(tile) ? WaterTileType::CoastRocks : WaterTileType::ClearRocks);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a cluster of rocks.
|
||||
* @param tile Initial tile.
|
||||
* @param count Number of rocks to attempt to place.
|
||||
*/
|
||||
void GenerateRocks(TileIndex tile, uint32_t count)
|
||||
{
|
||||
if (!TileMayHaveRocks(tile, false)) return;
|
||||
|
||||
for (;;) {
|
||||
TileMakeRocks(tile);
|
||||
MarkTileDirtyByTile(tile);
|
||||
|
||||
TileIndex tile_new;
|
||||
do {
|
||||
if (--count == 0) return;
|
||||
tile_new = tile + TileOffsByDiagDir(RandomRange(DiagDirection::End));
|
||||
} while (!TileMayHaveRocks(tile_new, true));
|
||||
tile = tile_new;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if a tile may have rough ground on.
|
||||
* @param tile The tile index.
|
||||
* @return true if the tile may have rough ground.
|
||||
*/
|
||||
static bool TileMayHaveRough(TileIndex tile)
|
||||
{
|
||||
return IsTileType(tile, TileType::Clear) && !IsClearGround(tile, ClearGround::Desert);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a cluster of rough ground.
|
||||
* @param tile Initial tile.
|
||||
* @param count Number of rough ground tiles to attempt to place.
|
||||
*/
|
||||
static void GenerateRough(TileIndex tile, uint32_t count)
|
||||
{
|
||||
if (!TileMayHaveRough(tile)) return;
|
||||
|
||||
for (;;) {
|
||||
SetClearGroundDensity(tile, ClearGround::Rough, 3);
|
||||
MarkTileDirtyByTile(tile);
|
||||
|
||||
TileIndex tile_new;
|
||||
do {
|
||||
if (--count == 0) return;
|
||||
tile_new = tile + TileOffsByDiagDir(RandomRange(DiagDirection::End));
|
||||
} while (!TileMayHaveRough(tile_new));
|
||||
tile = tile_new;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate rough and rocky features on clear tiles.
|
||||
*/
|
||||
void GenerateClearTile()
|
||||
{
|
||||
uint i, gi;
|
||||
TileIndex tile;
|
||||
|
||||
/* add rough tiles */
|
||||
i = Map::ScaleBySize(GB(Random(), 0, 10) + 0x400);
|
||||
gi = Map::ScaleBySize(GB(Random(), 0, 7) + 0x80);
|
||||
uint i = Map::ScaleBySize(GB(Random(), 0, 9) + 0x200);
|
||||
uint gi = Map::ScaleBySize(GB(Random(), 0, 7) + 0x80);
|
||||
|
||||
SetGeneratingWorldProgress(GenWorldProgress::RoughAndRocks, gi + i);
|
||||
|
||||
/* Add rough tiles. */
|
||||
do {
|
||||
uint32_t r = Random();
|
||||
IncreaseGeneratingWorldProgress(GenWorldProgress::RoughAndRocks);
|
||||
tile = RandomTile();
|
||||
if (IsTileType(tile, TileType::Clear) && !IsClearGround(tile, ClearGround::Desert)) SetClearGroundDensity(tile, ClearGround::Rough, 3);
|
||||
GenerateRough(RandomTileSeed(r), GB(r, 24, 3) + 1);
|
||||
} while (--i);
|
||||
|
||||
/* add rocky tiles */
|
||||
/* Add rocky tiles. */
|
||||
i = gi;
|
||||
do {
|
||||
uint32_t r = Random();
|
||||
tile = RandomTileSeed(r);
|
||||
|
||||
IncreaseGeneratingWorldProgress(GenWorldProgress::RoughAndRocks);
|
||||
if (IsTileType(tile, TileType::Clear)) {
|
||||
uint j = GB(r, 16, 4) + 5;
|
||||
for (;;) {
|
||||
TileIndex tile_new;
|
||||
|
||||
SetClearGroundDensity(tile, ClearGround::Rocks, 3);
|
||||
MarkTileDirtyByTile(tile);
|
||||
do {
|
||||
if (--j == 0) goto get_out;
|
||||
tile_new = tile + TileOffsByDiagDir((DiagDirection)GB(Random(), 0, 2));
|
||||
} while (!IsTileType(tile_new, TileType::Clear));
|
||||
tile = tile_new;
|
||||
}
|
||||
get_out:;
|
||||
}
|
||||
GenerateRocks(RandomTileSeed(r), GB(r, 24, 4) + 5);
|
||||
} while (--i);
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -12,7 +12,8 @@
|
||||
|
||||
#include "tile_cmd.h"
|
||||
|
||||
void DrawHillyLandTile(const TileInfo *ti);
|
||||
void DrawClearLandTile(const TileInfo *ti, uint8_t set);
|
||||
void DrawRoughLandTile(const TileInfo *ti);
|
||||
void DrawClearLandTile(const TileInfo *ti, uint8_t density);
|
||||
void GenerateRocks(TileIndex tile, uint32_t count);
|
||||
|
||||
#endif /* CLEAR_FUNC_H */
|
||||
|
||||
+1
-1
@@ -189,7 +189,7 @@ inline void SetFieldType(Tile t, uint f)
|
||||
inline IndustryID GetIndustryIndexOfField(Tile t)
|
||||
{
|
||||
assert(GetClearGround(t) == ClearGround::Fields);
|
||||
return(IndustryID) t.m2();
|
||||
return static_cast<IndustryID>(t.m2());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+4
-4
@@ -80,10 +80,10 @@ struct CommandInfo {
|
||||
};
|
||||
/* Helpers to generate the master command table from the command traits. */
|
||||
template <typename T>
|
||||
inline constexpr CommandInfo CommandFromTrait() noexcept { return { T::name, T::flags, T::type }; };
|
||||
constexpr CommandInfo CommandFromTrait() noexcept { return { T::name, T::flags, T::type }; };
|
||||
|
||||
template <typename T, T... i>
|
||||
inline constexpr auto MakeCommandsFromTraits(std::integer_sequence<T, i...>) noexcept {
|
||||
constexpr auto MakeCommandsFromTraits(std::integer_sequence<T, i...>) noexcept {
|
||||
return EnumIndexArray<CommandInfo, Commands, static_cast<Commands>(sizeof...(i))>{{{ CommandFromTrait<CommandTraits<static_cast<Commands>(i)>>()... }}};
|
||||
}
|
||||
|
||||
@@ -259,7 +259,7 @@ void CommandHelperBase::InternalPostResult(CommandCost &res, TileIndex tile, boo
|
||||
*/
|
||||
void CommandHelperBase::LogCommandExecution(Commands cmd, StringID err_message, const CommandDataBuffer &args, bool failed)
|
||||
{
|
||||
Debug(desync, 1, "{}: {:08x}; {:02x}; {:02x}; {:08x}; {:08x}; {} ({})", failed ? "cmdf" : "cmd", (uint32_t)TimerGameEconomy::date.base(), TimerGameEconomy::date_fract, _current_company, cmd, err_message, FormatArrayAsHex(args), GetCommandName(cmd));
|
||||
Debug(Facility::Desync, Severity::Error, "{}: {:08x}; {:02x}; {:02x}; {:08x}; {:08x}; {} ({})", failed ? "cmdf" : "cmd", (uint32_t)TimerGameEconomy::date.base(), TimerGameEconomy::date_fract, _current_company, cmd, err_message, FormatArrayAsHex(args), GetCommandName(cmd));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -324,7 +324,7 @@ std::tuple<bool, bool, bool> CommandHelperBase::InternalExecuteValidateTestAndPr
|
||||
BasePersistentStorageArray::SwitchMode(PSM_ENTER_COMMAND);
|
||||
}
|
||||
|
||||
return { false, _debug_desync_level >= 1, send_net };
|
||||
return { false, IsVisibleSeverity(Facility::Desync, Severity::Error), send_net };
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+3
-3
@@ -46,7 +46,7 @@ constexpr CommandFlags GetCommandFlags()
|
||||
* @param cmd_flags Flags from GetCommandFlags
|
||||
* @return flags for DoCommand
|
||||
*/
|
||||
static constexpr inline DoCommandFlags CommandFlagsToDCFlags(CommandFlags cmd_flags)
|
||||
static constexpr DoCommandFlags CommandFlagsToDCFlags(CommandFlags cmd_flags)
|
||||
{
|
||||
DoCommandFlags flags = {};
|
||||
if (cmd_flags.Test(CommandFlag::NoWater)) flags.Set(DoCommandFlag::NoWater);
|
||||
@@ -285,7 +285,7 @@ protected:
|
||||
static inline void SetClientIdHelper([[maybe_unused]] T &data)
|
||||
{
|
||||
if constexpr (std::is_same_v<ClientID, T>) {
|
||||
if (data == INVALID_CLIENT_ID) data = CLIENT_ID_SERVER;
|
||||
if (data == ClientID::Invalid) data = ClientID::Server;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -372,7 +372,7 @@ protected:
|
||||
static inline bool ClientIdIsSet([[maybe_unused]] T &data)
|
||||
{
|
||||
if constexpr (std::is_same_v<ClientID, T>) {
|
||||
return data != INVALID_CLIENT_ID;
|
||||
return data != ClientID::Invalid;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
|
||||
+2
-1
@@ -400,6 +400,7 @@ enum class DoCommandFlag : uint8_t {
|
||||
AllTiles, ///< allow this command also on TileType::Void tiles
|
||||
NoModifyTownRating, ///< do not change town rating
|
||||
ForceClearTile, ///< do not only remove the object on the tile, but also clear any water left on it
|
||||
ClearToRocks, ///< when clearing land, make rocks instead of bare dirt/grass
|
||||
};
|
||||
|
||||
/** Bitset of \c DoCommandFlag elements. */
|
||||
@@ -483,7 +484,7 @@ template <Commands Tcmd> struct CommandTraits;
|
||||
static constexpr auto &proc = proc_; \
|
||||
static constexpr CommandFlags flags = flags_; \
|
||||
static constexpr CommandType type = type_; \
|
||||
static inline constexpr std::string_view name = #proc_; \
|
||||
static constexpr std::string_view name = #proc_; \
|
||||
};
|
||||
|
||||
/** Storage buffer for serialized command data. */
|
||||
|
||||
+87
-59
@@ -37,12 +37,14 @@
|
||||
#include "goal_base.h"
|
||||
#include "story_base.h"
|
||||
#include "company_cmd.h"
|
||||
#include "script/api/script_event_types.hpp"
|
||||
#include "timer/timer.h"
|
||||
#include "timer/timer_game_economy.h"
|
||||
#include "timer/timer_game_tick.h"
|
||||
#include "timer/timer_window.h"
|
||||
#include "road_gui.h"
|
||||
|
||||
#include "widgets/company_widget.h"
|
||||
#include "widgets/statusbar_widget.h"
|
||||
|
||||
#include "table/strings.h"
|
||||
@@ -428,6 +430,44 @@ CommandCost CheckTileOwnership(TileIndex tile)
|
||||
return CheckOwnership(GetTileOwner(tile), tile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a company name based on type and seed, if the name is unique and shorter than the max length.
|
||||
* @param other_names List of names that cannot be used.
|
||||
* @param c The company of the name to set.
|
||||
* @param t The nearby town, for news message.
|
||||
* @param str The type of name.
|
||||
* @param strp The random seed.
|
||||
* @return True iff the name was set.
|
||||
*/
|
||||
static bool SetCompanyName(std::span<const std::string> other_names, Company *c, const Town *t, StringID str, uint32_t strp)
|
||||
{
|
||||
assert(c != nullptr);
|
||||
assert(t != nullptr);
|
||||
|
||||
/* Name must not be too long. */
|
||||
std::string name = GetString(str, strp);
|
||||
if (Utf8StringLength(name) >= MAX_LENGTH_COMPANY_NAME_CHARS) return false;
|
||||
|
||||
/* No companies must have this name already. */
|
||||
if (std::ranges::find(other_names, name) != other_names.end()) return false;
|
||||
|
||||
c->name_1 = str;
|
||||
c->name_2 = strp;
|
||||
|
||||
MarkWholeScreenDirty();
|
||||
AI::BroadcastNewEvent(new ScriptEventCompanyRenamed(c->index, name));
|
||||
Game::NewEvent(new ScriptEventCompanyRenamed(c->index, name));
|
||||
|
||||
if (!c->is_ai) return true;
|
||||
|
||||
auto cni = std::make_unique<CompanyNewsInformation>(STR_NEWS_COMPANY_LAUNCH_TITLE, c);
|
||||
EncodedString headline = GetEncodedString(STR_NEWS_COMPANY_LAUNCH_DESCRIPTION, cni->company_name, t->index);
|
||||
AddNewsItem(std::move(headline),
|
||||
NewsType::CompanyInfo, NewsStyle::Company, {}, c->last_build_coordinate, {}, std::move(cni));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the name of a company from the last build coordinate.
|
||||
* @param c Company to give a name.
|
||||
@@ -437,51 +477,24 @@ static void GenerateCompanyName(Company *c)
|
||||
if (c->name_1 != STR_SV_UNNAMED) return;
|
||||
if (c->last_build_coordinate == 0) return;
|
||||
|
||||
Town *t = ClosestTownFromTile(c->last_build_coordinate, UINT_MAX);
|
||||
/* Collect existing company names. */
|
||||
std::vector<std::string> other_names;
|
||||
for (const Company *cc : Company::Iterate()) {
|
||||
if (cc != c) other_names.emplace_back(GetString(STR_COMPANY_NAME, cc->index));
|
||||
}
|
||||
|
||||
StringID str;
|
||||
uint32_t strp;
|
||||
std::string name;
|
||||
const Town *t = ClosestTownFromTile(c->last_build_coordinate, UINT_MAX);
|
||||
|
||||
if (t->name.empty() && IsInsideMM(t->townnametype, SPECSTR_TOWNNAME_START, SPECSTR_TOWNNAME_END)) {
|
||||
str = t->townnametype - SPECSTR_TOWNNAME_START + SPECSTR_COMPANY_NAME_START;
|
||||
strp = t->townnameparts;
|
||||
|
||||
verify_name:;
|
||||
/* No companies must have this name already */
|
||||
for (const Company *cc : Company::Iterate()) {
|
||||
if (cc->name_1 == str && cc->name_2 == strp) goto bad_town_name;
|
||||
}
|
||||
|
||||
name = GetString(str, strp);
|
||||
if (Utf8StringLength(name) >= MAX_LENGTH_COMPANY_NAME_CHARS) goto bad_town_name;
|
||||
|
||||
set_name:;
|
||||
c->name_1 = str;
|
||||
c->name_2 = strp;
|
||||
|
||||
MarkWholeScreenDirty();
|
||||
AI::BroadcastNewEvent(new ScriptEventCompanyRenamed(c->index, name));
|
||||
Game::NewEvent(new ScriptEventCompanyRenamed(c->index, name));
|
||||
|
||||
if (c->is_ai) {
|
||||
auto cni = std::make_unique<CompanyNewsInformation>(STR_NEWS_COMPANY_LAUNCH_TITLE, c);
|
||||
EncodedString headline = GetEncodedString(STR_NEWS_COMPANY_LAUNCH_DESCRIPTION, cni->company_name, t->index);
|
||||
AddNewsItem(std::move(headline),
|
||||
NewsType::CompanyInfo, NewsStyle::Company, {}, c->last_build_coordinate, {}, std::move(cni));
|
||||
}
|
||||
return;
|
||||
if (SetCompanyName(other_names, c, t, SPECSTR_COMPANY_NAME_START + (t->townnametype - SPECSTR_TOWNNAME_START), t->townnameparts)) return;
|
||||
}
|
||||
bad_town_name:;
|
||||
|
||||
if (c->president_name_1 == SPECSTR_PRESIDENT_NAME) {
|
||||
str = SPECSTR_ANDCO_NAME;
|
||||
strp = c->president_name_2;
|
||||
name = GetString(str, strp);
|
||||
goto set_name;
|
||||
} else {
|
||||
str = SPECSTR_ANDCO_NAME;
|
||||
strp = Random();
|
||||
goto verify_name;
|
||||
if (SetCompanyName(other_names, c, t, SPECSTR_ANDCO_NAME, c->president_name_2)) return;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if (SetCompanyName(other_names, c, t, SPECSTR_ANDCO_NAME, Random())) return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -524,7 +537,7 @@ static Colours GenerateCompanyColour()
|
||||
}
|
||||
|
||||
/* Sort it according to the values in _colour_sort. */
|
||||
std::ranges::stable_sort(colours, {}, [](auto &i) { return _colour_sort[i]; });
|
||||
std::ranges::stable_sort(colours, std::greater_equal{}, [](auto &i) { return _colour_sort[i]; });
|
||||
|
||||
/* Move the colours that look similar to each company's colour to the side */
|
||||
for (const Company *c : Company::Iterate()) {
|
||||
@@ -541,29 +554,44 @@ static Colours GenerateCompanyColour()
|
||||
return colours.at(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a company's president name based on seed, if the name is unique and shorter than the max length.
|
||||
* @param other_names List of names that cannot be used.
|
||||
* @param c The company of the president name to set.
|
||||
* @param seed The random seed.
|
||||
* @return True iff the name was set.
|
||||
*/
|
||||
static bool SetPresidentName(std::span<const std::string> other_names, Company *c, uint32_t seed)
|
||||
{
|
||||
assert(c != nullptr);
|
||||
|
||||
c->president_name_1 = SPECSTR_PRESIDENT_NAME;
|
||||
c->president_name_2 = seed;
|
||||
|
||||
/* President name must not be too long. */
|
||||
std::string name = GetString(STR_PRESIDENT_NAME, c->index);
|
||||
if (Utf8StringLength(name) >= MAX_LENGTH_PRESIDENT_NAME_CHARS) return false;
|
||||
|
||||
/* No presidents must have this name already. */
|
||||
if (std::ranges::find(other_names, name) != other_names.end()) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random president name of a company.
|
||||
* @param c Company that needs a new president name.
|
||||
*/
|
||||
static void GeneratePresidentName(Company *c)
|
||||
{
|
||||
/* Collect existing president names. */
|
||||
std::vector<std::string> other_names;
|
||||
for (const Company *cc : Company::Iterate()) {
|
||||
if (cc != c) other_names.emplace_back(GetString(STR_PRESIDENT_NAME, cc->index));
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
restart:;
|
||||
c->president_name_2 = Random();
|
||||
c->president_name_1 = SPECSTR_PRESIDENT_NAME;
|
||||
|
||||
/* Reserve space for extra unicode character. We need to do this to be able
|
||||
* to detect too long president name. */
|
||||
std::string name = GetString(STR_PRESIDENT_NAME, c->index);
|
||||
if (Utf8StringLength(name) >= MAX_LENGTH_PRESIDENT_NAME_CHARS) continue;
|
||||
|
||||
for (const Company *cc : Company::Iterate()) {
|
||||
if (c != cc) {
|
||||
std::string other_name = GetString(STR_PRESIDENT_NAME, cc->index);
|
||||
if (name == other_name) goto restart;
|
||||
}
|
||||
}
|
||||
return;
|
||||
if (SetPresidentName(other_names, c, Random())) return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -671,7 +699,7 @@ TimeoutTimer<TimerGameTick> _new_competitor_timeout({ TimerGameTick::Priority::C
|
||||
|
||||
/* Send a command to all clients to start up a new AI.
|
||||
* Works fine for Multiplayer and Singleplayer */
|
||||
Command<Commands::CompanyControl>::Post(CompanyCtrlAction::NewAI, CompanyID::Invalid(), CompanyRemoveReason::None, INVALID_CLIENT_ID);
|
||||
Command<Commands::CompanyControl>::Post(CompanyCtrlAction::NewAI, CompanyID::Invalid(), CompanyRemoveReason::None, ClientID::Invalid);
|
||||
});
|
||||
|
||||
/** Start of a new game. */
|
||||
@@ -792,7 +820,7 @@ void OnTick_Companies()
|
||||
for (auto i = 0; i < _settings_game.difficulty.max_no_competitors; i++) {
|
||||
if (_networking && num_companies++ >= _settings_client.network.max_companies) break;
|
||||
if (num_ais++ >= _settings_game.difficulty.max_no_competitors) break;
|
||||
Command<Commands::CompanyControl>::Post(CompanyCtrlAction::NewAI, CompanyID::Invalid(), {}, INVALID_CLIENT_ID);
|
||||
Command<Commands::CompanyControl>::Post(CompanyCtrlAction::NewAI, CompanyID::Invalid(), {}, ClientID::Invalid);
|
||||
}
|
||||
timeout = 10 * 60 * Ticks::TICKS_PER_SECOND;
|
||||
}
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
#include "company_type.h"
|
||||
#include "livery.h"
|
||||
|
||||
enum ClientID : uint32_t;
|
||||
enum class ClientID : uint32_t;
|
||||
enum class Colours : uint8_t;
|
||||
|
||||
CommandCost CmdCompanyCtrl(DoCommandFlags flags, CompanyCtrlAction cca, CompanyID company_id, CompanyRemoveReason reason, ClientID client_id);
|
||||
|
||||
+18
-18
@@ -188,12 +188,12 @@ static void DrawCategories(const Rect &r)
|
||||
{
|
||||
int y = r.top;
|
||||
/* Draw description of 12-minute economic period. */
|
||||
DrawString(r.left, r.right, y, (TimerGameEconomy::UsingWallclockUnits() ? STR_FINANCES_PERIOD_CAPTION : STR_FINANCES_YEAR_CAPTION), TextColour::FromString, SA_LEFT, true);
|
||||
DrawString(r.left, r.right, y, (TimerGameEconomy::UsingWallclockUnits() ? STR_FINANCES_PERIOD_CAPTION : STR_FINANCES_YEAR_CAPTION), TextColour::FromString, AlignmentH::Start, true);
|
||||
y += GetCharacterHeight(FontSize::Normal) + WidgetDimensions::scaled.vsep_wide;
|
||||
|
||||
for (const ExpensesList &list : _expenses_list_types) {
|
||||
/* Draw category title and advance y */
|
||||
DrawString(r.left, r.right, y, list.title, TextColour::FromString, SA_LEFT);
|
||||
DrawString(r.left, r.right, y, list.title, TextColour::FromString, AlignmentH::Start);
|
||||
y += GetCharacterHeight(FontSize::Normal);
|
||||
|
||||
/* Draw category items and advance y */
|
||||
@@ -204,7 +204,7 @@ static void DrawCategories(const Rect &r)
|
||||
y += WidgetDimensions::scaled.vsep_normal;
|
||||
|
||||
/* Draw category total and advance y */
|
||||
DrawString(r.left, r.right, y, STR_FINANCES_TOTAL_CAPTION, TextColour::FromString, SA_RIGHT);
|
||||
DrawString(r.left, r.right, y, STR_FINANCES_TOTAL_CAPTION, TextColour::FromString, AlignmentH::End);
|
||||
y += GetCharacterHeight(FontSize::Normal);
|
||||
|
||||
/* Advance y by a blockspace after this category block */
|
||||
@@ -213,7 +213,7 @@ static void DrawCategories(const Rect &r)
|
||||
|
||||
/* Draw total profit/loss */
|
||||
y += WidgetDimensions::scaled.vsep_normal;
|
||||
DrawString(r.left, r.right, y, STR_FINANCES_PROFIT, TextColour::FromString, SA_LEFT);
|
||||
DrawString(r.left, r.right, y, STR_FINANCES_PROFIT, TextColour::FromString, AlignmentH::Start);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -233,7 +233,7 @@ static void DrawPrice(Money amount, int left, int right, int top, TextColour col
|
||||
amount = -amount;
|
||||
str = STR_FINANCES_POSITIVE_INCOME;
|
||||
}
|
||||
DrawString(left, right, top, GetString(str, amount), colour, SA_RIGHT | SA_FORCE);
|
||||
DrawString(left, right, top, GetString(str, amount), colour, AlignmentH::ForceRight);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -279,7 +279,7 @@ static void DrawYearColumn(const Rect &r, TimerGameEconomy::Year year, const Exp
|
||||
Money sum;
|
||||
|
||||
/* Year header */
|
||||
DrawString(r.left, r.right, y, GetString(STR_FINANCES_YEAR, year), TextColour::FromString, SA_RIGHT | SA_FORCE, true);
|
||||
DrawString(r.left, r.right, y, GetString(STR_FINANCES_YEAR, year), TextColour::FromString, AlignmentH::ForceRight, true);
|
||||
y += GetCharacterHeight(FontSize::Normal) + WidgetDimensions::scaled.vsep_wide;
|
||||
|
||||
/* Categories */
|
||||
@@ -322,10 +322,10 @@ static constexpr std::initializer_list<NWidgetPart> _nested_company_finances_wid
|
||||
NWidget(WWT_TEXT, Colours::Invalid), SetStringTip(STR_FINANCES_BANK_BALANCE_TITLE), SetPadding(WidgetDimensions::unscaled.vsep_normal, 0, 0, 0),
|
||||
EndContainer(),
|
||||
NWidget(NWID_VERTICAL), // Vertical column with bank balance amount, loan amount, and total.
|
||||
NWidget(WWT_TEXT, Colours::Invalid, WID_CF_OWN_VALUE), SetAlignment(SA_VERT_CENTER | SA_RIGHT | SA_FORCE),
|
||||
NWidget(WWT_TEXT, Colours::Invalid, WID_CF_LOAN_VALUE), SetAlignment(SA_VERT_CENTER | SA_RIGHT | SA_FORCE),
|
||||
NWidget(WWT_TEXT, Colours::Invalid, WID_CF_OWN_VALUE), SetAlignment({AlignmentH::ForceRight, AlignmentV::Middle}),
|
||||
NWidget(WWT_TEXT, Colours::Invalid, WID_CF_LOAN_VALUE), SetAlignment({AlignmentH::ForceRight, AlignmentV::Middle}),
|
||||
NWidget(WWT_EMPTY, Colours::Invalid, WID_CF_BALANCE_LINE), SetMinimalSize(0, WidgetDimensions::unscaled.vsep_normal),
|
||||
NWidget(WWT_TEXT, Colours::Invalid, WID_CF_BALANCE_VALUE), SetAlignment(SA_VERT_CENTER | SA_RIGHT | SA_FORCE),
|
||||
NWidget(WWT_TEXT, Colours::Invalid, WID_CF_BALANCE_VALUE), SetAlignment({AlignmentH::ForceRight, AlignmentV::Middle}),
|
||||
EndContainer(),
|
||||
NWidget(NWID_SELECTION, Colours::Invalid, WID_CF_SEL_MAXLOAN),
|
||||
NWidget(NWID_VERTICAL), SetPIPRatio(0, 0, 1), // Max loan information
|
||||
@@ -1794,14 +1794,14 @@ struct CompanyInfrastructureWindow : Window
|
||||
case InfrastructureItemType::Total:
|
||||
/* Draw line in the spacer above the total. */
|
||||
GfxFillRect(costr.Translate(0, -WidgetDimensions::scaled.vsep_normal).WithHeight(WidgetDimensions::scaled.fullbevel.top), PC_WHITE);
|
||||
DrawString(costr, GetString(TimerGameEconomy::UsingWallclockUnits() ? STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_PERIOD : STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_YEAR, it->cost * 12), TextColour::Black, SA_RIGHT | SA_FORCE);
|
||||
DrawString(costr, GetString(TimerGameEconomy::UsingWallclockUnits() ? STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_PERIOD : STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_YEAR, it->cost * 12), TextColour::Black, AlignmentH::ForceRight);
|
||||
break;
|
||||
|
||||
case InfrastructureItemType::Value:
|
||||
DrawString(labelr.Indent(WidgetDimensions::scaled.hsep_indent, rtl), GetString(it->label), TextColour::White);
|
||||
DrawString(countr, GetString(STR_JUST_COMMA, it->count), TextColour::White, SA_RIGHT | SA_FORCE);
|
||||
DrawString(countr, GetString(STR_JUST_COMMA, it->count), TextColour::White, AlignmentH::ForceRight);
|
||||
if (_settings_game.economy.infrastructure_maintenance) {
|
||||
DrawString(costr, GetString(TimerGameEconomy::UsingWallclockUnits() ? STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_PERIOD : STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_YEAR, it->cost * 12), TextColour::Black, SA_RIGHT | SA_FORCE);
|
||||
DrawString(costr, GetString(TimerGameEconomy::UsingWallclockUnits() ? STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_PERIOD : STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_YEAR, it->cost * 12), TextColour::Black, AlignmentH::ForceRight);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1875,7 +1875,7 @@ static constexpr std::initializer_list<NWidgetPart> _nested_company_widgets = {
|
||||
NWidget(WWT_EMPTY, Colours::Invalid, WID_C_DESC_COLOUR_SCHEME_EXAMPLE), SetMinimalSize(30, 0), SetFill(1, 1),
|
||||
EndContainer(),
|
||||
NWidget(NWID_HORIZONTAL), SetPIP(0, WidgetDimensions::unscaled.hsep_normal, 0),
|
||||
NWidget(WWT_TEXT, Colours::Invalid, WID_C_DESC_VEHICLE), SetStringTip(STR_COMPANY_VIEW_VEHICLES_TITLE), SetAlignment(SA_LEFT | SA_TOP),
|
||||
NWidget(WWT_TEXT, Colours::Invalid, WID_C_DESC_VEHICLE), SetStringTip(STR_COMPANY_VIEW_VEHICLES_TITLE), SetAlignment({AlignmentH::Start, AlignmentV::Top}),
|
||||
NWidget(WWT_EMPTY, Colours::Invalid, WID_C_DESC_VEHICLE_COUNTS), SetMinimalTextLines(4, 0), SetFill(1, 1),
|
||||
EndContainer(),
|
||||
EndContainer(),
|
||||
@@ -1894,7 +1894,7 @@ static constexpr std::initializer_list<NWidgetPart> _nested_company_widgets = {
|
||||
NWidget(WWT_TEXT, Colours::Invalid, WID_C_DESC_COMPANY_VALUE), SetFill(1, 0),
|
||||
|
||||
NWidget(NWID_HORIZONTAL), SetPIP(0, WidgetDimensions::unscaled.hsep_normal, 0),
|
||||
NWidget(WWT_TEXT, Colours::Invalid, WID_C_DESC_INFRASTRUCTURE), SetStringTip(STR_COMPANY_VIEW_INFRASTRUCTURE), SetAlignment(SA_LEFT | SA_TOP),
|
||||
NWidget(WWT_TEXT, Colours::Invalid, WID_C_DESC_INFRASTRUCTURE), SetStringTip(STR_COMPANY_VIEW_INFRASTRUCTURE), SetAlignment({AlignmentH::Start, AlignmentV::Top}),
|
||||
NWidget(WWT_EMPTY, Colours::Invalid, WID_C_DESC_INFRASTRUCTURE_COUNTS), SetMinimalTextLines(5, 0), SetFill(1, 0),
|
||||
NWidget(NWID_VERTICAL), SetPIPRatio(0, 0, 1),
|
||||
NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_C_VIEW_INFRASTRUCTURE), SetStringTip(STR_COMPANY_VIEW_INFRASTRUCTURE_BUTTON, STR_COMPANY_VIEW_INFRASTRUCTURE_TOOLTIP),
|
||||
@@ -2021,7 +2021,7 @@ struct CompanyWindow : Window
|
||||
break;
|
||||
|
||||
case WID_C_DESC_VEHICLE_COUNTS: {
|
||||
uint64_t max_value = GetParamMaxValue(5000); // Maximum number of vehicles
|
||||
uint64_t max_value = GetParamMaxValue(10000); // Maximum number of vehicles
|
||||
for (const auto &count_string : _company_view_vehicle_count_strings) {
|
||||
size.width = std::max(size.width, GetStringBoundingBox(GetString(count_string, max_value)).width + padding.width);
|
||||
}
|
||||
@@ -2123,7 +2123,7 @@ struct CompanyWindow : Window
|
||||
break;
|
||||
|
||||
case WID_C_FACE_TITLE:
|
||||
DrawStringMultiLine(r, GetString(STR_COMPANY_VIEW_PRESIDENT_MANAGER_TITLE, c->index), TextColour::FromString, SA_HOR_CENTER);
|
||||
DrawStringMultiLine(r, GetString(STR_COMPANY_VIEW_PRESIDENT_MANAGER_TITLE, c->index), TextColour::FromString, AlignmentH::Centre);
|
||||
break;
|
||||
|
||||
case WID_C_DESC_COLOUR_SCHEME_EXAMPLE: {
|
||||
@@ -2244,7 +2244,7 @@ struct CompanyWindow : Window
|
||||
this->query_widget = WID_C_COMPANY_JOIN;
|
||||
CompanyID company = this->window_number;
|
||||
if (_network_server) {
|
||||
NetworkServerDoMove(CLIENT_ID_SERVER, company);
|
||||
NetworkServerDoMove(ClientID::Server, company);
|
||||
MarkWholeScreenDirty();
|
||||
} else {
|
||||
/* just send the join command */
|
||||
@@ -2389,7 +2389,7 @@ struct BuyCompanyWindow : Window {
|
||||
|
||||
case WID_BC_QUESTION: {
|
||||
const Company *c = Company::Get(this->window_number);
|
||||
DrawStringMultiLine(r, GetString(this->hostile_takeover ? STR_BUY_COMPANY_HOSTILE_TAKEOVER : STR_BUY_COMPANY_MESSAGE, c->index, this->company_value), TextColour::FromString, SA_CENTER);
|
||||
DrawStringMultiLine(r, GetString(this->hostile_takeover ? STR_BUY_COMPANY_HOSTILE_TAKEOVER : STR_BUY_COMPANY_MESSAGE, c->index, this->company_value), TextColour::FromString, {AlignmentH::Centre, AlignmentV::Middle});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
#include "company_type.h"
|
||||
#include "gfx_type.h"
|
||||
|
||||
#include "table/strings.h"
|
||||
|
||||
/** Ways a FaceVar should be interpreted. */
|
||||
enum class FaceVarType : uint8_t {
|
||||
Sprite, ///< FaceVar describes an offset to the given SpriteID.
|
||||
@@ -33,7 +31,7 @@ struct FaceVar {
|
||||
uint8_t length; ///< Number of bits used in the CompanyManagerFace
|
||||
uint8_t valid_values; ///< The number of valid values
|
||||
std::variant<SpriteID, uint64_t, std::pair<uint64_t, uint64_t>> data; ///< The first sprite
|
||||
StringID name = STR_NULL; ///< Name of the configurable component of the face.
|
||||
StringID name{}; ///< Name of the configurable component of the face.
|
||||
|
||||
/**
|
||||
* Gets the company manager's face bits.
|
||||
|
||||
+5
-5
@@ -40,7 +40,7 @@ std::optional<FileHandle> _iconsole_output_file;
|
||||
void IConsoleInit()
|
||||
{
|
||||
_iconsole_output_file = std::nullopt;
|
||||
_redirect_console_to_client = INVALID_CLIENT_ID;
|
||||
_redirect_console_to_client = ClientID::Invalid;
|
||||
_redirect_console_to_admin = AdminID::Invalid();
|
||||
|
||||
IConsoleGUIInit();
|
||||
@@ -91,7 +91,7 @@ void IConsolePrint(ExtendedTextColour colour_code, const std::string &string)
|
||||
{
|
||||
assert(IsValidConsoleColour(colour_code));
|
||||
|
||||
if (_redirect_console_to_client != INVALID_CLIENT_ID) {
|
||||
if (_redirect_console_to_client != ClientID::Invalid) {
|
||||
/* Redirect the string to the client */
|
||||
NetworkServerSendRcon(_redirect_console_to_client, colour_code, string);
|
||||
return;
|
||||
@@ -184,7 +184,7 @@ static std::string RemoveUnderscores(std::string name)
|
||||
*/
|
||||
static void IConsoleAliasExec(const IConsoleAlias *alias, std::span<std::string> tokens, uint recurse_count)
|
||||
{
|
||||
Debug(console, 6, "Requested command is an alias; parsing...");
|
||||
Debug(Facility::Console, Severity::Debug2, "Requested command is an alias; parsing...");
|
||||
|
||||
if (recurse_count > ICON_MAX_RECURSE) {
|
||||
IConsolePrint(CC_ERROR, "Too many alias expansions, recursion limit reached.");
|
||||
@@ -272,7 +272,7 @@ void IConsoleCmdExec(std::string_view command_string, const uint recurse_count)
|
||||
{
|
||||
if (command_string[0] == '#') return; // comments
|
||||
|
||||
Debug(console, 4, "Executing cmdline: '{}'", command_string);
|
||||
Debug(Facility::Console, Severity::Info, "Executing cmdline: '{}'", command_string);
|
||||
|
||||
std::string buffer;
|
||||
StringBuilder builder{buffer};
|
||||
@@ -331,7 +331,7 @@ void IConsoleCmdExec(std::string_view command_string, const uint recurse_count)
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < tokens.size(); i++) {
|
||||
Debug(console, 8, "Token {} is: '{}'", i, tokens[i]);
|
||||
Debug(Facility::Console, Severity::Trace2, "Token {} is: '{}'", i, tokens[i]);
|
||||
}
|
||||
|
||||
if (tokens.empty() || tokens[0].empty()) return; // don't execute empty commands
|
||||
|
||||
+39
-54
@@ -13,7 +13,7 @@
|
||||
#include "debug.h"
|
||||
#include "engine_func.h"
|
||||
#include "landscape.h"
|
||||
#include "saveload/saveload.h"
|
||||
#include "saveload/saveload_func.h"
|
||||
#include "network/core/network_game_info.h"
|
||||
#include "network/network.h"
|
||||
#include "network/network_func.h"
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "fontcache.h"
|
||||
#include "screenshot.h"
|
||||
#include "genworld.h"
|
||||
#include "string_func.h"
|
||||
#include "strings_func.h"
|
||||
#include "viewport_func.h"
|
||||
#include "window_func.h"
|
||||
@@ -698,7 +699,7 @@ static bool ConKickOrBan(std::string_view arg, bool ban, std::string_view reason
|
||||
* kicking frees closes and subsequently free the connection related instances, which we
|
||||
* would be reading from and writing to after returning. So we would read or write data
|
||||
* from freed memory up till the segfault triggers. */
|
||||
if (*client_id == CLIENT_ID_SERVER || *client_id == _redirect_console_to_client) {
|
||||
if (*client_id == ClientID::Server || *client_id == _redirect_console_to_client) {
|
||||
IConsolePrint(CC_ERROR, "You can not {} yourself!", ban ? "ban" : "kick");
|
||||
return true;
|
||||
}
|
||||
@@ -945,7 +946,7 @@ static bool ConClientNickChange(std::span<std::string_view> argv)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (*client_id == CLIENT_ID_SERVER) {
|
||||
if (*client_id == ClientID::Server) {
|
||||
IConsolePrint(CC_ERROR, "Please use the command 'name' to change your own name!");
|
||||
return true;
|
||||
}
|
||||
@@ -1024,7 +1025,7 @@ static bool ConJoinCompany(std::span<std::string_view> argv)
|
||||
|
||||
/* non-dedicated server may just do the move! */
|
||||
if (_network_server) {
|
||||
NetworkServerDoMove(CLIENT_ID_SERVER, *company_id);
|
||||
NetworkServerDoMove(ClientID::Server, *company_id);
|
||||
} else {
|
||||
NetworkClientRequestMove(*company_id);
|
||||
}
|
||||
@@ -1070,7 +1071,7 @@ static bool ConMoveClient(std::span<std::string_view> argv)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ci->client_id == CLIENT_ID_SERVER && _network_dedicated) {
|
||||
if (ci->client_id == ClientID::Server && _network_dedicated) {
|
||||
IConsolePrint(CC_ERROR, "You cannot move the server!");
|
||||
return true;
|
||||
}
|
||||
@@ -1118,7 +1119,7 @@ static bool ConResetCompany(std::span<std::string_view> argv)
|
||||
IConsolePrint(CC_ERROR, "Cannot remove company: a client is connected to that company.");
|
||||
return false;
|
||||
}
|
||||
const NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER);
|
||||
const NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(ClientID::Server);
|
||||
assert(ci != nullptr);
|
||||
if (ci->client_playas == *index) {
|
||||
IConsolePrint(CC_ERROR, "Cannot remove company: the server is connected to that company.");
|
||||
@@ -1126,7 +1127,7 @@ static bool ConResetCompany(std::span<std::string_view> argv)
|
||||
}
|
||||
|
||||
/* It is safe to remove this company */
|
||||
Command<Commands::CompanyControl>::Post(CompanyCtrlAction::Delete, *index, CompanyRemoveReason::Manual, INVALID_CLIENT_ID);
|
||||
Command<Commands::CompanyControl>::Post(CompanyCtrlAction::Delete, *index, CompanyRemoveReason::Manual, ClientID::Invalid);
|
||||
IConsolePrint(CC_DEFAULT, "Company deleted.");
|
||||
|
||||
return true;
|
||||
@@ -1563,7 +1564,7 @@ static bool ConStartAI(std::span<std::string_view> argv)
|
||||
}
|
||||
|
||||
/* Start a new AI company */
|
||||
Command<Commands::CompanyControl>::Post(CompanyCtrlAction::NewAI, CompanyID::Invalid(), CompanyRemoveReason::None, INVALID_CLIENT_ID);
|
||||
Command<Commands::CompanyControl>::Post(CompanyCtrlAction::NewAI, CompanyID::Invalid(), CompanyRemoveReason::None, ClientID::Invalid);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1605,8 +1606,8 @@ static bool ConReloadAI(std::span<std::string_view> argv)
|
||||
}
|
||||
|
||||
/* First kill the company of the AI, then start a new one. This should start the current AI again */
|
||||
Command<Commands::CompanyControl>::Post(CompanyCtrlAction::Delete, *company_id, CompanyRemoveReason::Manual, INVALID_CLIENT_ID);
|
||||
Command<Commands::CompanyControl>::Post(CompanyCtrlAction::NewAI, *company_id, CompanyRemoveReason::None, INVALID_CLIENT_ID);
|
||||
Command<Commands::CompanyControl>::Post(CompanyCtrlAction::Delete, *company_id, CompanyRemoveReason::Manual, ClientID::Invalid);
|
||||
Command<Commands::CompanyControl>::Post(CompanyCtrlAction::NewAI, *company_id, CompanyRemoveReason::None, ClientID::Invalid);
|
||||
IConsolePrint(CC_DEFAULT, "AI reloaded.");
|
||||
|
||||
return true;
|
||||
@@ -1649,7 +1650,7 @@ static bool ConStopAI(std::span<std::string_view> argv)
|
||||
}
|
||||
|
||||
/* Now kill the company of the AI. */
|
||||
Command<Commands::CompanyControl>::Post(CompanyCtrlAction::Delete, *company_id, CompanyRemoveReason::Manual, INVALID_CLIENT_ID);
|
||||
Command<Commands::CompanyControl>::Post(CompanyCtrlAction::Delete, *company_id, CompanyRemoveReason::Manual, ClientID::Invalid);
|
||||
IConsolePrint(CC_DEFAULT, "AI stopped, company deleted.");
|
||||
|
||||
return true;
|
||||
@@ -2050,7 +2051,7 @@ static bool ConSay(std::span<std::string_view> argv)
|
||||
NetworkClientSendChat(NetworkAction::ChatBroadcast, NetworkChatDestinationType::Broadcast, 0 /* param does not matter */, argv[1]);
|
||||
} else {
|
||||
bool from_admin = (_redirect_console_to_admin < AdminID::Invalid());
|
||||
NetworkServerSendChat(NetworkAction::ChatBroadcast, NetworkChatDestinationType::Broadcast, 0, argv[1], CLIENT_ID_SERVER, from_admin);
|
||||
NetworkServerSendChat(NetworkAction::ChatBroadcast, NetworkChatDestinationType::Broadcast, 0, argv[1], ClientID::Server, from_admin);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -2082,7 +2083,7 @@ static bool ConSayCompany(std::span<std::string_view> argv)
|
||||
NetworkClientSendChat(NetworkAction::ChatTeam, NetworkChatDestinationType::Team, company_id->base(), argv[2]);
|
||||
} else {
|
||||
bool from_admin = (_redirect_console_to_admin < AdminID::Invalid());
|
||||
NetworkServerSendChat(NetworkAction::ChatTeam, NetworkChatDestinationType::Team, company_id->base(), argv[2], CLIENT_ID_SERVER, from_admin);
|
||||
NetworkServerSendChat(NetworkAction::ChatTeam, NetworkChatDestinationType::Team, company_id->base(), argv[2], ClientID::Server, from_admin);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -2106,10 +2107,10 @@ static bool ConSayClient(std::span<std::string_view> argv)
|
||||
}
|
||||
|
||||
if (!_network_server) {
|
||||
NetworkClientSendChat(NetworkAction::ChatClient, NetworkChatDestinationType::Client, *client_id, argv[2]);
|
||||
NetworkClientSendChat(NetworkAction::ChatClient, NetworkChatDestinationType::Client, to_underlying(*client_id), argv[2]);
|
||||
} else {
|
||||
bool from_admin = (_redirect_console_to_admin < AdminID::Invalid());
|
||||
NetworkServerSendChat(NetworkAction::ChatClient, NetworkChatDestinationType::Client, *client_id, argv[2], CLIENT_ID_SERVER, from_admin);
|
||||
NetworkServerSendChat(NetworkAction::ChatClient, NetworkChatDestinationType::Client, to_underlying(*client_id), argv[2], ClientID::Server, from_admin);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -2657,7 +2658,7 @@ static bool ConNewGRFProfile(std::span<std::string_view> argv)
|
||||
bool active = selected && profiler->active;
|
||||
TextColour tc = active ? TextColour::LightBlue : selected ? TextColour::Green : CC_INFO;
|
||||
std::string_view statustext = active ? " (active)" : selected ? " (selected)" : "";
|
||||
IConsolePrint(tc, "{}: [{:08X}] {}{}", i, std::byteswap(grf.grfid), grf.filename, statustext);
|
||||
IConsolePrint(tc, "{}: [{}] {}{}", i, FormatArrayAsHex(grf.grfid), grf.filename, statustext);
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
@@ -2673,7 +2674,7 @@ static bool ConNewGRFProfile(std::span<std::string_view> argv)
|
||||
}
|
||||
const GRFFile *grf = &files[*grfnum - 1];
|
||||
if (std::any_of(_newgrf_profilers.begin(), _newgrf_profilers.end(), [&](NewGRFProfiler &pr) { return pr.grffile == grf; })) {
|
||||
IConsolePrint(CC_WARNING, "GRF number {} [{:08X}] is already selected for profiling.", *grfnum, std::byteswap(grf->grfid));
|
||||
IConsolePrint(CC_WARNING, "GRF number {} [{}] is already selected for profiling.", *grfnum, FormatArrayAsHex(grf->grfid));
|
||||
continue;
|
||||
}
|
||||
_newgrf_profilers.emplace_back(grf);
|
||||
@@ -2709,7 +2710,7 @@ static bool ConNewGRFProfile(std::span<std::string_view> argv)
|
||||
started++;
|
||||
|
||||
if (!grfids.empty()) grfids += ", ";
|
||||
format_append(grfids, "[{:08X}]", std::byteswap(pr.grffile->grfid));
|
||||
format_append(grfids, "[{}]", FormatArrayAsHex(pr.grffile->grfid));
|
||||
}
|
||||
}
|
||||
if (started > 0) {
|
||||
@@ -2792,22 +2793,6 @@ static bool ConFramerateWindow(std::span<std::string_view> argv)
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a label as a string.
|
||||
* If all elements are visible ASCII (excluding space) then the label will be formatted as a string of 4 characters,
|
||||
* otherwise it will be output as an 8-digit hexadecimal value.
|
||||
* @param label Label to format.
|
||||
* @return string representation of label.
|
||||
**/
|
||||
static std::string FormatLabel(uint32_t label)
|
||||
{
|
||||
if (std::isgraph(GB(label, 24, 8)) && std::isgraph(GB(label, 16, 8)) && std::isgraph(GB(label, 8, 8)) && std::isgraph(GB(label, 0, 8))) {
|
||||
return fmt::format("{:c}{:c}{:c}{:c}", GB(label, 24, 8), GB(label, 16, 8), GB(label, 8, 8), GB(label, 0, 8));
|
||||
}
|
||||
|
||||
return fmt::format("{:08X}", label);
|
||||
}
|
||||
|
||||
/** List all road types and their configuration. */
|
||||
static void ConDumpRoadTypes()
|
||||
{
|
||||
@@ -2818,31 +2803,31 @@ static void ConDumpRoadTypes()
|
||||
IConsolePrint(CC_DEFAULT, " h = hidden");
|
||||
IConsolePrint(CC_DEFAULT, " T = buildable by towns");
|
||||
|
||||
std::map<uint32_t, const GRFFile *> grfs;
|
||||
std::map<GrfID, const GRFFile *> grfs;
|
||||
for (RoadType rt : EnumRange(ROADTYPE_END)) {
|
||||
const RoadTypeInfo *rti = GetRoadTypeInfo(rt);
|
||||
if (rti->label == 0) continue;
|
||||
uint32_t grfid = 0;
|
||||
if (rti->label.Empty()) continue;
|
||||
GrfID grfid{};
|
||||
const GRFFile *grf = rti->grffile[RoadSpriteType::Ground];
|
||||
if (grf != nullptr) {
|
||||
grfid = grf->grfid;
|
||||
grfs.emplace(grfid, grf);
|
||||
}
|
||||
IConsolePrint(CC_DEFAULT, " {:02d} {} {}, Flags: {}{}{}{}{}, GRF: {:08X}, {}",
|
||||
IConsolePrint(CC_DEFAULT, " {:02d} {} {}, Flags: {}{}{}{}{}, GRF: {}, {}",
|
||||
(uint)rt,
|
||||
RoadTypeIsTram(rt) ? "Tram" : "Road",
|
||||
FormatLabel(rti->label),
|
||||
rti->label.AsString(),
|
||||
rti->flags.Test(RoadTypeFlag::Catenary) ? 'c' : '-',
|
||||
rti->flags.Test(RoadTypeFlag::NoLevelCrossing) ? 'l' : '-',
|
||||
rti->flags.Test(RoadTypeFlag::NoHouses) ? 'X' : '-',
|
||||
rti->flags.Test(RoadTypeFlag::Hidden) ? 'h' : '-',
|
||||
rti->flags.Test(RoadTypeFlag::TownBuild) ? 'T' : '-',
|
||||
std::byteswap(grfid),
|
||||
FormatArrayAsHex(grfid),
|
||||
GetStringPtr(rti->strings.name)
|
||||
);
|
||||
}
|
||||
for (const auto &grf : grfs) {
|
||||
IConsolePrint(CC_DEFAULT, " GRF: {:08X} = {}", std::byteswap(grf.first), grf.second->filename);
|
||||
IConsolePrint(CC_DEFAULT, " GRF: {} = {}", FormatArrayAsHex(grf.first), grf.second->filename);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2857,31 +2842,31 @@ static void ConDumpRailTypes()
|
||||
IConsolePrint(CC_DEFAULT, " a = always allow 90 degree turns");
|
||||
IConsolePrint(CC_DEFAULT, " d = always disallow 90 degree turns");
|
||||
|
||||
std::map<uint32_t, const GRFFile *> grfs;
|
||||
std::map<GrfID, const GRFFile *> grfs;
|
||||
for (RailType rt : EnumRange(RAILTYPE_END)) {
|
||||
const RailTypeInfo *rti = GetRailTypeInfo(rt);
|
||||
if (rti->label == 0) continue;
|
||||
uint32_t grfid = 0;
|
||||
if (rti->label.Empty()) continue;
|
||||
GrfID grfid{};
|
||||
const GRFFile *grf = rti->grffile[RailSpriteType::Ground];
|
||||
if (grf != nullptr) {
|
||||
grfid = grf->grfid;
|
||||
grfs.emplace(grfid, grf);
|
||||
}
|
||||
IConsolePrint(CC_DEFAULT, " {:02d} {}, Flags: {}{}{}{}{}{}, GRF: {:08X}, {}",
|
||||
IConsolePrint(CC_DEFAULT, " {:02d} {}, Flags: {}{}{}{}{}{}, GRF: {}, {}",
|
||||
(uint)rt,
|
||||
FormatLabel(rti->label),
|
||||
rti->label.AsString(),
|
||||
rti->flags.Test(RailTypeFlag::Catenary) ? 'c' : '-',
|
||||
rti->flags.Test(RailTypeFlag::NoLevelCrossing) ? 'l' : '-',
|
||||
rti->flags.Test(RailTypeFlag::Hidden) ? 'h' : '-',
|
||||
rti->flags.Test(RailTypeFlag::NoSpriteCombine) ? 's' : '-',
|
||||
rti->flags.Test(RailTypeFlag::Allow90Deg) ? 'a' : '-',
|
||||
rti->flags.Test(RailTypeFlag::Disallow90Deg) ? 'd' : '-',
|
||||
std::byteswap(grfid),
|
||||
FormatArrayAsHex(grfid),
|
||||
GetStringPtr(rti->strings.name)
|
||||
);
|
||||
}
|
||||
for (const auto &grf : grfs) {
|
||||
IConsolePrint(CC_DEFAULT, " GRF: {:08X} = {}", std::byteswap(grf.first), grf.second->filename);
|
||||
IConsolePrint(CC_DEFAULT, " GRF: {} = {}", FormatArrayAsHex(grf.first), grf.second->filename);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2906,18 +2891,18 @@ static void ConDumpCargoTypes()
|
||||
IConsolePrint(CC_DEFAULT, " i = non-potable");
|
||||
IConsolePrint(CC_DEFAULT, " S = special");
|
||||
|
||||
std::map<uint32_t, const GRFFile *> grfs;
|
||||
std::map<GrfID, const GRFFile *> grfs;
|
||||
for (const CargoSpec *spec : CargoSpec::Iterate()) {
|
||||
uint32_t grfid = 0;
|
||||
GrfID grfid{};
|
||||
const GRFFile *grf = spec->grffile;
|
||||
if (grf != nullptr) {
|
||||
grfid = grf->grfid;
|
||||
grfs.emplace(grfid, grf);
|
||||
}
|
||||
IConsolePrint(CC_DEFAULT, " {:02d} Bit: {:2d}, Label: {}, Callback mask: 0x{:02X}, Cargo class: {}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}, GRF: {:08X}, {}",
|
||||
IConsolePrint(CC_DEFAULT, " {:02d} Bit: {:2d}, Label: {}, Callback mask: 0x{:02X}, Cargo class: {}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}, GRF: {}, {}",
|
||||
spec->Index(),
|
||||
spec->bitnum,
|
||||
FormatLabel(spec->label.base()),
|
||||
spec->label.AsString(),
|
||||
spec->callback_mask.base(),
|
||||
spec->classes.Test(CargoClass::Passengers) ? 'p' : '-',
|
||||
spec->classes.Test(CargoClass::Mail) ? 'm' : '-',
|
||||
@@ -2935,12 +2920,12 @@ static void ConDumpCargoTypes()
|
||||
spec->classes.Test(CargoClass::Potable) ? 'e' : '-',
|
||||
spec->classes.Test(CargoClass::NonPotable) ? 'i' : '-',
|
||||
spec->classes.Test(CargoClass::Special) ? 'S' : '-',
|
||||
std::byteswap(grfid),
|
||||
FormatArrayAsHex(grfid),
|
||||
GetStringPtr(spec->name)
|
||||
);
|
||||
}
|
||||
for (const auto &grf : grfs) {
|
||||
IConsolePrint(CC_DEFAULT, " GRF: {:08X} = {}", std::byteswap(grf.first), grf.second->filename);
|
||||
IConsolePrint(CC_DEFAULT, " GRF: {} = {}", FormatArrayAsHex(grf.first), grf.second->filename);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -200,23 +200,23 @@ struct IConsoleWindow : Window
|
||||
int ypos = this->height - this->line_height - WidgetDimensions::scaled.hsep_normal;
|
||||
for (size_t line_index = IConsoleWindow::scroll; line_index < _iconsole_buffer.size(); line_index++) {
|
||||
const IConsoleLine &print = _iconsole_buffer[line_index];
|
||||
ypos = DrawStringMultiLine(WidgetDimensions::scaled.frametext.left, right, -this->line_height, ypos, GetString(STR_JUST_RAW_STRING, print.buffer), print.colour, SA_LEFT | SA_BOTTOM | SA_FORCE) - WidgetDimensions::scaled.hsep_normal;
|
||||
ypos = DrawStringMultiLine(WidgetDimensions::scaled.frametext.left, right, -this->line_height, ypos, GetString(STR_JUST_RAW_STRING, print.buffer), print.colour, {AlignmentH::ForceLeft, AlignmentV::Bottom}) - WidgetDimensions::scaled.hsep_normal;
|
||||
if (ypos < 0) break;
|
||||
}
|
||||
/* If the text is longer than the window, don't show the starting ']' */
|
||||
int delta = this->width - WidgetDimensions::scaled.frametext.right - cursor_width - this->line_offset - _iconsole_cmdline.pixels - ICON_RIGHT_BORDERWIDTH;
|
||||
if (delta > 0) {
|
||||
DrawString(WidgetDimensions::scaled.frametext.left, right, this->height - this->line_height, "]", CC_COMMAND, SA_LEFT | SA_FORCE);
|
||||
DrawString(WidgetDimensions::scaled.frametext.left, right, this->height - this->line_height, "]", CC_COMMAND, AlignmentH::ForceLeft);
|
||||
delta = 0;
|
||||
}
|
||||
|
||||
/* If we have a marked area, draw a background highlight. */
|
||||
if (_iconsole_cmdline.marklength != 0) GfxFillRect(this->line_offset + delta + _iconsole_cmdline.markxoffs, this->height - this->line_height, this->line_offset + delta + _iconsole_cmdline.markxoffs + _iconsole_cmdline.marklength, this->height - 1, PC_DARK_RED);
|
||||
|
||||
DrawString(this->line_offset + delta, right, this->height - this->line_height, _iconsole_cmdline.GetText(), CC_COMMAND, SA_LEFT | SA_FORCE);
|
||||
DrawString(this->line_offset + delta, right, this->height - this->line_height, _iconsole_cmdline.GetText(), CC_COMMAND, AlignmentH::ForceLeft);
|
||||
|
||||
if (_focused_window == this && _iconsole_cmdline.caret) {
|
||||
DrawString(this->line_offset + delta + _iconsole_cmdline.caretxoffs, right, this->height - this->line_height, "_", TextColour::White, SA_LEFT | SA_FORCE);
|
||||
DrawString(this->line_offset + delta + _iconsole_cmdline.caretxoffs, right, this->height - this->line_height, "_", TextColour::White, AlignmentH::ForceLeft);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@ add_files(
|
||||
geometry_func.hpp
|
||||
geometry_type.hpp
|
||||
kdtree.hpp
|
||||
label.cpp
|
||||
label_type.hpp
|
||||
math_func.cpp
|
||||
math_func.hpp
|
||||
multimap.hpp
|
||||
|
||||
@@ -48,7 +48,7 @@ struct Backup {
|
||||
if (this->valid) {
|
||||
/* We cannot assert here, as missing restoration is 'normal' when exceptions are thrown.
|
||||
* Exceptions are especially used to abort world generation. */
|
||||
Debug(misc, 0, "{}:{}: Backed-up value was not restored!", this->location.file_name(), this->location.line());
|
||||
Debug(Facility::Misc, Severity::Critical, "{}:{}: Backed-up value was not restored!", this->location.file_name(), this->location.line());
|
||||
this->Restore();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ public:
|
||||
* Set all bits.
|
||||
* @returns The bit set
|
||||
*/
|
||||
inline constexpr Timpl &Set()
|
||||
constexpr Timpl &Set()
|
||||
{
|
||||
this->data = Tmask;
|
||||
return static_cast<Timpl&>(*this);
|
||||
@@ -48,13 +48,15 @@ public:
|
||||
|
||||
/**
|
||||
* Set the value-th bit.
|
||||
* @tparam Treturn_type The returned type to which this bit set will be cast.
|
||||
* @param value Bit to set.
|
||||
* @returns The bit set
|
||||
*/
|
||||
inline constexpr Timpl &Set(Tvalue_type value)
|
||||
template <typename Treturn_type = Timpl> requires std::is_base_of_v<BaseBitSet<Timpl, Tvalue_type, Tstorage, Tmask>, Treturn_type>
|
||||
constexpr Treturn_type &Set(Tvalue_type value)
|
||||
{
|
||||
this->data |= (1ULL << Timpl::DecayValueType(value));
|
||||
return static_cast<Timpl&>(*this);
|
||||
return static_cast<Treturn_type &>(*this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,7 +64,7 @@ public:
|
||||
* @param other Bitset of values to set.
|
||||
* @returns The bit set
|
||||
*/
|
||||
inline constexpr Timpl &Set(const Timpl &other)
|
||||
constexpr Timpl &Set(const Timpl &other)
|
||||
{
|
||||
this->data |= other.data;
|
||||
return static_cast<Timpl&>(*this);
|
||||
@@ -74,7 +76,7 @@ public:
|
||||
* @param set true if the bit should be set, false if the bit should be reset.
|
||||
* @returns The EnumBitset
|
||||
*/
|
||||
inline constexpr Timpl &Set(Tvalue_type value, bool set)
|
||||
constexpr Timpl &Set(Tvalue_type value, bool set)
|
||||
{
|
||||
return set ? this->Set(value) : this->Reset(value);
|
||||
}
|
||||
@@ -83,7 +85,7 @@ public:
|
||||
* Reset all bits.
|
||||
* @returns The bit set
|
||||
*/
|
||||
inline constexpr Timpl &Reset()
|
||||
constexpr Timpl &Reset()
|
||||
{
|
||||
this->data = 0;
|
||||
return static_cast<Timpl &>(*this);
|
||||
@@ -94,7 +96,7 @@ public:
|
||||
* @param value Bit to reset.
|
||||
* @returns The bit set
|
||||
*/
|
||||
inline constexpr Timpl &Reset(Tvalue_type value)
|
||||
constexpr Timpl &Reset(Tvalue_type value)
|
||||
{
|
||||
this->data &= ~(1ULL << Timpl::DecayValueType(value));
|
||||
return static_cast<Timpl&>(*this);
|
||||
@@ -105,7 +107,7 @@ public:
|
||||
* @param other Bitset of values to reset.
|
||||
* @returns The bit set
|
||||
*/
|
||||
inline constexpr Timpl &Reset(const Timpl &other)
|
||||
constexpr Timpl &Reset(const Timpl &other)
|
||||
{
|
||||
this->data &= ~other.data;
|
||||
return static_cast<Timpl&>(*this);
|
||||
@@ -115,7 +117,7 @@ public:
|
||||
* Flip all bits.
|
||||
* @returns The bit set
|
||||
*/
|
||||
inline constexpr Timpl &Flip()
|
||||
constexpr Timpl &Flip()
|
||||
{
|
||||
this->data ^= Tmask;
|
||||
return static_cast<Timpl &>(*this);
|
||||
@@ -126,7 +128,7 @@ public:
|
||||
* @param value Bit to flip.
|
||||
* @returns The bit set
|
||||
*/
|
||||
inline constexpr Timpl &Flip(Tvalue_type value)
|
||||
constexpr Timpl &Flip(Tvalue_type value)
|
||||
{
|
||||
if (this->Test(value)) {
|
||||
return this->Reset(value);
|
||||
@@ -140,7 +142,7 @@ public:
|
||||
* @param other Bitset of values to flip.
|
||||
* @returns The bit set
|
||||
*/
|
||||
inline constexpr Timpl &Flip(const Timpl &other)
|
||||
constexpr Timpl &Flip(const Timpl &other)
|
||||
{
|
||||
this->data ^= other.data;
|
||||
return static_cast<Timpl&>(*this);
|
||||
@@ -151,7 +153,7 @@ public:
|
||||
* @param value Bit to check.
|
||||
* @returns true iff the requested bit is set.
|
||||
*/
|
||||
inline constexpr bool Test(Tvalue_type value) const
|
||||
constexpr bool Test(Tvalue_type value) const
|
||||
{
|
||||
return (this->data & (1ULL << Timpl::DecayValueType(value))) != 0;
|
||||
}
|
||||
@@ -161,7 +163,7 @@ public:
|
||||
* @param other BitSet of values to test.
|
||||
* @returns true iff all of the values are set.
|
||||
*/
|
||||
inline constexpr bool All(const Timpl &other) const
|
||||
constexpr bool All(const Timpl &other) const
|
||||
{
|
||||
return (this->data & other.data) == other.data;
|
||||
}
|
||||
@@ -170,7 +172,7 @@ public:
|
||||
* Test if all of the values are set.
|
||||
* @returns true iff all of the values are set.
|
||||
*/
|
||||
inline constexpr bool All() const
|
||||
constexpr bool All() const
|
||||
{
|
||||
return this->data == Tmask;
|
||||
}
|
||||
@@ -180,7 +182,7 @@ public:
|
||||
* @param other BitSet of values to test.
|
||||
* @returns true iff any of the given values are set.
|
||||
*/
|
||||
inline constexpr bool Any(const Timpl &other) const
|
||||
constexpr bool Any(const Timpl &other) const
|
||||
{
|
||||
return (this->data & other.data) != 0;
|
||||
}
|
||||
@@ -189,7 +191,7 @@ public:
|
||||
* Test if any of the values are set.
|
||||
* @returns true iff any of the values are set.
|
||||
*/
|
||||
inline constexpr bool Any() const
|
||||
constexpr bool Any() const
|
||||
{
|
||||
return this->data != 0;
|
||||
}
|
||||
@@ -198,29 +200,29 @@ public:
|
||||
* Test if none of the values are set.
|
||||
* @returns true iff none of the values are set.
|
||||
*/
|
||||
inline constexpr bool None() const
|
||||
constexpr bool None() const
|
||||
{
|
||||
return this->data == 0;
|
||||
}
|
||||
|
||||
inline constexpr Timpl &operator|=(const Timpl &other)
|
||||
constexpr Timpl &operator|=(const Timpl &other)
|
||||
{
|
||||
this->data |= other.data;
|
||||
return static_cast<Timpl &>(*this);
|
||||
}
|
||||
|
||||
inline constexpr Timpl operator|(const Timpl &other) const
|
||||
constexpr Timpl operator|(const Timpl &other) const
|
||||
{
|
||||
return Timpl{static_cast<Tstorage>(this->data | other.data)};
|
||||
}
|
||||
|
||||
inline constexpr Timpl &operator&=(const Timpl &other)
|
||||
constexpr Timpl &operator&=(const Timpl &other)
|
||||
{
|
||||
this->data &= other.data;
|
||||
return static_cast<Timpl &>(*this);
|
||||
}
|
||||
|
||||
inline constexpr Timpl operator&(const Timpl &other) const
|
||||
constexpr Timpl operator&(const Timpl &other) const
|
||||
{
|
||||
return Timpl{static_cast<Tstorage>(this->data & other.data)};
|
||||
}
|
||||
@@ -229,7 +231,7 @@ public:
|
||||
* Retrieve the raw value behind this bit set.
|
||||
* @returns the raw value.
|
||||
*/
|
||||
inline constexpr Tstorage base() const noexcept
|
||||
constexpr Tstorage base() const noexcept
|
||||
{
|
||||
return this->data;
|
||||
}
|
||||
@@ -238,7 +240,7 @@ public:
|
||||
* Test that the raw value of this bit set is valid.
|
||||
* @returns true iff the no bits outside the masked value are set.
|
||||
*/
|
||||
inline constexpr bool IsValid() const
|
||||
constexpr bool IsValid() const
|
||||
{
|
||||
return (this->base() & Tmask) == this->base();
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
* @return The selected bits, aligned to a LSB.
|
||||
*/
|
||||
template <typename T>
|
||||
[[debug_inline]] inline constexpr static uint GB(const T x, const uint8_t s, const uint8_t n)
|
||||
[[debug_inline]] static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
|
||||
{
|
||||
return (x >> s) & (((T)1U << n) - 1);
|
||||
}
|
||||
@@ -100,7 +100,7 @@ constexpr T AB(T &x, const uint8_t s, const uint8_t n, const U i)
|
||||
* @return True if the bit is set, false else.
|
||||
*/
|
||||
template <typename T>
|
||||
[[debug_inline]] inline constexpr bool HasBit(const T x, const uint8_t y)
|
||||
[[debug_inline]] constexpr bool HasBit(const T x, const uint8_t y)
|
||||
{
|
||||
return (x & ((T)1U << y)) != 0;
|
||||
}
|
||||
|
||||
+35
-20
@@ -38,7 +38,7 @@ constexpr bool is_enum_incrementable_v = is_enum_incrementable<enum_type>::value
|
||||
* @return Reference to the incremented enum.
|
||||
*/
|
||||
template <typename enum_type, std::enable_if_t<is_enum_incrementable_v<enum_type>, bool> = true>
|
||||
inline constexpr enum_type &operator ++(enum_type &e)
|
||||
constexpr enum_type &operator ++(enum_type &e)
|
||||
{
|
||||
e = static_cast<enum_type>(to_underlying(e) + 1);
|
||||
return e;
|
||||
@@ -50,7 +50,7 @@ inline constexpr enum_type &operator ++(enum_type &e)
|
||||
* @return Copy of the original value.
|
||||
*/
|
||||
template <typename enum_type, std::enable_if_t<is_enum_incrementable_v<enum_type>, bool> = true>
|
||||
inline constexpr enum_type operator ++(enum_type &e, int)
|
||||
constexpr enum_type operator ++(enum_type &e, int)
|
||||
{
|
||||
enum_type e_org = e;
|
||||
++e;
|
||||
@@ -63,7 +63,7 @@ inline constexpr enum_type operator ++(enum_type &e, int)
|
||||
* @return Reference to the decremented enum.
|
||||
*/
|
||||
template <typename enum_type, std::enable_if_t<is_enum_incrementable_v<enum_type>, bool> = true>
|
||||
inline constexpr enum_type &operator --(enum_type &e)
|
||||
constexpr enum_type &operator --(enum_type &e)
|
||||
{
|
||||
e = static_cast<enum_type>(to_underlying(e) - 1);
|
||||
return e;
|
||||
@@ -75,7 +75,7 @@ inline constexpr enum_type &operator --(enum_type &e)
|
||||
* @return Copy of the original value.
|
||||
*/
|
||||
template <typename enum_type, std::enable_if_t<is_enum_incrementable_v<enum_type>, bool> = true>
|
||||
inline constexpr enum_type operator --(enum_type &e, int)
|
||||
constexpr enum_type operator --(enum_type &e, int)
|
||||
{
|
||||
enum_type e_org = e;
|
||||
--e;
|
||||
@@ -104,13 +104,13 @@ constexpr bool is_enum_sequential_v = is_enum_sequential<enum_type>::value;
|
||||
* @return The new enum.
|
||||
*/
|
||||
template <typename enum_type, std::enable_if_t<is_enum_sequential_v<enum_type>, bool> = true>
|
||||
inline constexpr enum_type operator+(enum_type e, int offset)
|
||||
constexpr enum_type operator+(enum_type e, int offset)
|
||||
{
|
||||
return static_cast<enum_type>(to_underlying(e) + offset);
|
||||
}
|
||||
|
||||
template <typename enum_type, std::enable_if_t<is_enum_sequential_v<enum_type>, bool> = true>
|
||||
inline constexpr enum_type &operator+=(enum_type &e, int offset)
|
||||
constexpr enum_type &operator+=(enum_type &e, int offset)
|
||||
{
|
||||
e = e + offset;
|
||||
return e;
|
||||
@@ -123,13 +123,13 @@ inline constexpr enum_type &operator+=(enum_type &e, int offset)
|
||||
* @return The new enum.
|
||||
*/
|
||||
template <typename enum_type, std::enable_if_t<is_enum_sequential_v<enum_type>, bool> = true>
|
||||
inline constexpr enum_type operator-(enum_type e, int offset)
|
||||
constexpr enum_type operator-(enum_type e, int offset)
|
||||
{
|
||||
return static_cast<enum_type>(to_underlying(e) - offset);
|
||||
}
|
||||
|
||||
template <typename enum_type, std::enable_if_t<is_enum_sequential_v<enum_type>, bool> = true>
|
||||
inline constexpr enum_type &operator-=(enum_type &e, int offset)
|
||||
constexpr enum_type &operator-=(enum_type &e, int offset)
|
||||
{
|
||||
e = e - offset;
|
||||
return e;
|
||||
@@ -142,7 +142,7 @@ inline constexpr enum_type &operator-=(enum_type &e, int offset)
|
||||
* @return The value of the first enum minus the value of the second enum.
|
||||
*/
|
||||
template <typename enum_type, std::enable_if_t<is_enum_sequential_v<enum_type>, bool> = true>
|
||||
inline constexpr auto operator-(enum_type a, enum_type b)
|
||||
constexpr auto operator-(enum_type a, enum_type b)
|
||||
{
|
||||
return to_underlying(a) - to_underlying(b);
|
||||
}
|
||||
@@ -155,13 +155,13 @@ inline constexpr auto operator-(enum_type a, enum_type b)
|
||||
|
||||
/** Operators to allow to work with enum as with type safe bit set in C++ */
|
||||
#define DECLARE_ENUM_AS_BIT_SET(enum_type) \
|
||||
inline constexpr enum_type operator | (enum_type m1, enum_type m2) { return static_cast<enum_type>(to_underlying(m1) | to_underlying(m2)); } \
|
||||
inline constexpr enum_type operator & (enum_type m1, enum_type m2) { return static_cast<enum_type>(to_underlying(m1) & to_underlying(m2)); } \
|
||||
inline constexpr enum_type operator ^ (enum_type m1, enum_type m2) { return static_cast<enum_type>(to_underlying(m1) ^ to_underlying(m2)); } \
|
||||
inline constexpr enum_type& operator |= (enum_type& m1, enum_type m2) { m1 = m1 | m2; return m1; } \
|
||||
inline constexpr enum_type& operator &= (enum_type& m1, enum_type m2) { m1 = m1 & m2; return m1; } \
|
||||
inline constexpr enum_type& operator ^= (enum_type& m1, enum_type m2) { m1 = m1 ^ m2; return m1; } \
|
||||
inline constexpr enum_type operator ~(enum_type m) { return static_cast<enum_type>(~to_underlying(m)); }
|
||||
constexpr enum_type operator | (enum_type m1, enum_type m2) { return static_cast<enum_type>(to_underlying(m1) | to_underlying(m2)); } \
|
||||
constexpr enum_type operator & (enum_type m1, enum_type m2) { return static_cast<enum_type>(to_underlying(m1) & to_underlying(m2)); } \
|
||||
constexpr enum_type operator ^ (enum_type m1, enum_type m2) { return static_cast<enum_type>(to_underlying(m1) ^ to_underlying(m2)); } \
|
||||
constexpr enum_type& operator |= (enum_type& m1, enum_type m2) { m1 = m1 | m2; return m1; } \
|
||||
constexpr enum_type& operator &= (enum_type& m1, enum_type m2) { m1 = m1 & m2; return m1; } \
|
||||
constexpr enum_type& operator ^= (enum_type& m1, enum_type m2) { m1 = m1 ^ m2; return m1; } \
|
||||
constexpr enum_type operator ~(enum_type m) { return static_cast<enum_type>(~to_underlying(m)); }
|
||||
|
||||
/** Operator that allows this enumeration to be added to any other enumeration. */
|
||||
#define DECLARE_ENUM_AS_ADDABLE(EnumType) \
|
||||
@@ -181,7 +181,7 @@ inline constexpr auto operator-(enum_type a, enum_type b)
|
||||
* @return True iff the flag is set.
|
||||
*/
|
||||
template <typename T, class = typename std::enable_if_t<std::is_enum_v<T>>>
|
||||
[[debug_inline]] inline constexpr bool HasFlag(const T x, const T y)
|
||||
[[debug_inline]] constexpr bool HasFlag(const T x, const T y)
|
||||
{
|
||||
return (x & y) == y;
|
||||
}
|
||||
@@ -192,7 +192,7 @@ template <typename T, class = typename std::enable_if_t<std::is_enum_v<T>>>
|
||||
* @param y The flag to toggle.
|
||||
*/
|
||||
template <typename T, class = typename std::enable_if_t<std::is_enum_v<T>>>
|
||||
[[debug_inline]] inline constexpr void ToggleFlag(T &x, const T y)
|
||||
[[debug_inline]] constexpr void ToggleFlag(T &x, const T y)
|
||||
{
|
||||
if (HasFlag(x, y)) {
|
||||
x &= ~y;
|
||||
@@ -304,7 +304,19 @@ public:
|
||||
using EnumType = BaseClass::ValueType;
|
||||
|
||||
constexpr EnumBitSet() : BaseClass() {}
|
||||
constexpr EnumBitSet(Tenum value) : BaseClass() { this->Set(value); }
|
||||
|
||||
/**
|
||||
* Construct an EnumBitSet from an enum value.
|
||||
* @param value The single enum value to be set.
|
||||
*/
|
||||
constexpr EnumBitSet(Tenum value) : BaseClass()
|
||||
{
|
||||
/* MSVC 19.44 and older does not consider cast of dynamic type (e.g. BaseBitSet) to EnumBitSet as constant,
|
||||
* when the EnumBitSet is constructed inside an initializer list like we do for many lookup tables.
|
||||
* By setting the return type to BaseClass the cast becomes redundant and compilation does not fail. */
|
||||
this->template Set<BaseClass>(value);
|
||||
}
|
||||
|
||||
explicit constexpr EnumBitSet(Tstorage data) : BaseClass(data) {}
|
||||
|
||||
/**
|
||||
@@ -314,7 +326,10 @@ public:
|
||||
constexpr EnumBitSet(std::initializer_list<const Tenum> values) : BaseClass()
|
||||
{
|
||||
for (const Tenum &value : values) {
|
||||
this->Set(value);
|
||||
/* MSVC 19.44 and older does not consider cast of dynamic type (e.g. BaseBitSet) to EnumBitSet as constant,
|
||||
* when the EnumBitSet is constructed inside an initializer list like we do for many lookup tables.
|
||||
* By setting the return type to BaseClass the cast becomes redundant and compilation does not fail. */
|
||||
this->template Set<BaseClass>(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,9 +10,24 @@
|
||||
#include "../stdafx.h"
|
||||
#include "geometry_func.hpp"
|
||||
#include "math_func.hpp"
|
||||
#include "../strings_func.h"
|
||||
#include "../strings_type.h"
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
/**
|
||||
* Resolve horizontal alignment for the current text direction.
|
||||
* @return The resolved horizontal alignment.
|
||||
*/
|
||||
AlignmentH Alignment::ResolveRTL() const
|
||||
{
|
||||
switch (this->h) {
|
||||
case AlignmentH::Start: return _current_text_dir == TD_RTL ? AlignmentH::ForceRight : AlignmentH::ForceLeft;
|
||||
case AlignmentH::End: return _current_text_dir == TD_RTL ? AlignmentH::ForceLeft : AlignmentH::ForceRight;
|
||||
default: return this->h;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute bounding box of both dimensions.
|
||||
* @param d1 First dimension.
|
||||
|
||||
@@ -16,6 +16,43 @@
|
||||
# define Point OTTD_Point
|
||||
#endif /* __APPLE__ */
|
||||
|
||||
/** Horizontal alignments. */
|
||||
enum class AlignmentH : uint8_t {
|
||||
Start, ///< Align to the start, LTR/RTL aware.
|
||||
Centre, ///< Align to the centre.
|
||||
End, ///< Align to the end, LTR/RTL aware.
|
||||
ForceLeft, ///< Force align to the left.
|
||||
ForceRight, ///< Force align to the right.
|
||||
};
|
||||
|
||||
/** Vertical alignments. */
|
||||
enum class AlignmentV : uint8_t {
|
||||
Top, ///< Align to the top.
|
||||
Middle, ///< Align to the middle.
|
||||
Bottom, ///< Align to the bottom.
|
||||
};
|
||||
|
||||
/** Horizontal and vertical alignment. */
|
||||
struct Alignment {
|
||||
AlignmentH h; ///< Horizontal alignment.
|
||||
AlignmentV v; ///< Vertical alignment.
|
||||
|
||||
/**
|
||||
* Construct an alignment with the specified horizontal and vertical alignment.
|
||||
* @param h The horizontal alignment.
|
||||
* @param v The vertical alignment.
|
||||
*/
|
||||
constexpr Alignment(AlignmentH h, AlignmentV v) : h(h), v(v) {}
|
||||
|
||||
/**
|
||||
* Construct an alignment with the specific horizontal alignment.
|
||||
* @param h The horizontal alignment.
|
||||
*/
|
||||
constexpr Alignment(AlignmentH h) : Alignment(h, AlignmentV::Top) {}
|
||||
|
||||
AlignmentH ResolveRTL() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Determine where to position a centred object.
|
||||
* @param min The top or left coordinate.
|
||||
@@ -66,11 +103,19 @@ using Point = Coord2D<int>;
|
||||
|
||||
/** Dimensions (a width and height) of a rectangle in 2D */
|
||||
struct Dimension {
|
||||
uint width;
|
||||
uint height;
|
||||
using value_type = uint32_t; ///< The type of the values; hack to make this look enough like a std::array for saving/loading resolutions
|
||||
value_type width = 0; ///< The width of the rectangle.
|
||||
value_type height = 0; ///< The height of the rectangle.
|
||||
|
||||
constexpr Dimension() : width(0), height(0) {}
|
||||
constexpr Dimension(uint w, uint h) : width(w), height(h) {}
|
||||
/** Create a 0x0 dimension. */
|
||||
constexpr Dimension() = default;
|
||||
|
||||
/**
|
||||
* Create a dimension.
|
||||
* @param w The width.
|
||||
* @param h The height.
|
||||
*/
|
||||
constexpr Dimension(value_type w, value_type h) : width(w), height(h) {}
|
||||
|
||||
bool operator< (const Dimension &other) const
|
||||
{
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||
* OpenTTD 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 General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
|
||||
*/
|
||||
|
||||
/** @file label.cpp Implementation of label functions. */
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include "label_type.hpp"
|
||||
#include "../string_func.h"
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
/**
|
||||
* Get the label as a \c std::string.
|
||||
* If the label is all \c std::isgraph characters, it will return these characters as string,
|
||||
* otherwise it will format it as a 8-digit hexadecimal.
|
||||
* @return The label as string.
|
||||
*/
|
||||
std::string BaseLabel::AsString() const
|
||||
{
|
||||
if (std::ranges::all_of(*this, [](uint8_t c) { return std::isgraph(c); })) {
|
||||
return std::string{reinterpret_cast<const char *>(this->data()), this->size()};
|
||||
}
|
||||
|
||||
return FormatArrayAsHex(*this);
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||
* OpenTTD 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 General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
|
||||
*/
|
||||
|
||||
/** @file label_type.hpp A type for 4 character labels/tags/ids in files that should be read/shown as is. */
|
||||
|
||||
#ifndef LABEL_TYPE_HPP
|
||||
#define LABEL_TYPE_HPP
|
||||
|
||||
/** Base for a four character label/tag/id. */
|
||||
struct BaseLabel : std::array<uint8_t, 4> {
|
||||
/**
|
||||
* Check whether the label is empty.
|
||||
* @return \c true iff the label is empty, i.e. all zeros.
|
||||
*/
|
||||
constexpr bool Empty() const
|
||||
{
|
||||
return std::ranges::all_of(*this, [](uint8_t b) { return b == 0; });
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the label as a \c std::string.
|
||||
* If the label is all \c std::isgraph characters, it will return these characters as string,
|
||||
* otherwise it will format it as a 8-digit hexadecimal.
|
||||
* @return The label as string.
|
||||
*/
|
||||
std::string AsString() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* A four character label/tag/id.
|
||||
* @tparam Tag Type to distinguish labels/tags/ids of different types.
|
||||
*/
|
||||
template <typename Tag>
|
||||
struct Label : BaseLabel {
|
||||
/** Create an empty label, i.e. all zeros. */
|
||||
constexpr Label()
|
||||
{
|
||||
std::ranges::fill(*this, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a label with the given 4 letter character string.
|
||||
* @param label The label value.
|
||||
* @note This defines 5 characters, but the 5th character is assumed to null-terminator.
|
||||
*/
|
||||
constexpr Label(const char (&label)[5])
|
||||
{
|
||||
std::copy(label, label + this->size(), this->begin());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a label with the given 4 bytes.
|
||||
* @param label The label value.
|
||||
*/
|
||||
constexpr Label(const uint8_t (&label)[4])
|
||||
{
|
||||
std::copy(label, label + this->size(), this->begin());
|
||||
}
|
||||
|
||||
/**
|
||||
* Default spaceship operator.
|
||||
* @param other The label to compare to.
|
||||
* @return The comparison ordering.
|
||||
*/
|
||||
constexpr std::strong_ordering operator<=>(const Label<Tag> &other) const = default;
|
||||
};
|
||||
|
||||
#endif /* LABEL_TYPE_HPP */
|
||||
@@ -252,6 +252,10 @@ constexpr bool IsInsideBS(const T x, const size_t base, const size_t size)
|
||||
return static_cast<size_t>(x - base) < size;
|
||||
}
|
||||
|
||||
/** Specialization of IsInsideBS for #ConvertibleThroughBase. @copydoc IsInsideBS(const T, const size_t, const size_t) */
|
||||
template <ConvertibleThroughBase T>
|
||||
constexpr bool IsInsideBS(const T x, const T base, const size_t size) noexcept { return IsInsideBS(x.base(), base.base(), size); }
|
||||
|
||||
/**
|
||||
* Checks if a value is in an interval.
|
||||
*
|
||||
@@ -271,6 +275,10 @@ constexpr bool IsInsideMM(const size_t x, const size_t min, const size_t max) no
|
||||
/** Specialization of IsInsideMM for #ConvertibleThroughBase. @copydoc IsInsideMM(const size_t, const size_t, const size_t) */
|
||||
constexpr bool IsInsideMM(const ConvertibleThroughBase auto x, const size_t min, const size_t max) noexcept { return IsInsideMM(x.base(), min, max); }
|
||||
|
||||
/** Specialization of IsInsideMM for #ConvertibleThroughBase. @copydoc IsInsideMM(const size_t, const size_t, const size_t) */
|
||||
template <ConvertibleThroughBase T>
|
||||
constexpr bool IsInsideMM(const T x, const T min, const T max) noexcept { return IsInsideMM(x.base(), min.base(), max.base()); }
|
||||
|
||||
/** Specialization of IsInsideMM for enums. @copydoc IsInsideMM(const size_t, const size_t, const size_t) */
|
||||
template <typename enum_type, std::enable_if_t<std::is_enum_v<enum_type>, bool> = true>
|
||||
constexpr bool IsInsideMM(enum_type x, enum_type min, enum_type max) noexcept
|
||||
|
||||
@@ -42,10 +42,10 @@ public:
|
||||
constexpr OverflowSafeInt(const OverflowSafeInt &other) : m_value(other.m_value) { }
|
||||
constexpr OverflowSafeInt(const T int_) : m_value(int_) { }
|
||||
|
||||
inline constexpr OverflowSafeInt& operator = (const OverflowSafeInt& other) { this->m_value = other.m_value; return *this; }
|
||||
inline constexpr OverflowSafeInt& operator = (T other) { this->m_value = other; return *this; }
|
||||
constexpr OverflowSafeInt& operator = (const OverflowSafeInt& other) { this->m_value = other.m_value; return *this; }
|
||||
constexpr OverflowSafeInt& operator = (T other) { this->m_value = other; return *this; }
|
||||
|
||||
inline constexpr OverflowSafeInt operator - () const { return OverflowSafeInt(this->m_value == T_MIN ? T_MAX : -this->m_value); }
|
||||
constexpr OverflowSafeInt operator - () const { return OverflowSafeInt(this->m_value == T_MIN ? T_MAX : -this->m_value); }
|
||||
|
||||
/**
|
||||
* Safe implementation of addition.
|
||||
@@ -53,7 +53,7 @@ public:
|
||||
* @return Reference to this instance.
|
||||
* @note when the addition would yield more than T_MAX, it will be T_MAX.
|
||||
*/
|
||||
inline constexpr OverflowSafeInt& operator += (const OverflowSafeInt& other)
|
||||
constexpr OverflowSafeInt& operator += (const OverflowSafeInt& other)
|
||||
{
|
||||
#ifdef HAS_OVERFLOW_BUILTINS
|
||||
if (__builtin_add_overflow(this->m_value, other.m_value, &this->m_value)) [[unlikely]] {
|
||||
@@ -77,7 +77,7 @@ public:
|
||||
* @return Reference to this instance.
|
||||
* @note when the subtraction would yield less than T_MIN, it will be T_MIN.
|
||||
*/
|
||||
inline constexpr OverflowSafeInt& operator -= (const OverflowSafeInt& other)
|
||||
constexpr OverflowSafeInt& operator -= (const OverflowSafeInt& other)
|
||||
{
|
||||
#ifdef HAS_OVERFLOW_BUILTINS
|
||||
if (__builtin_sub_overflow(this->m_value, other.m_value, &this->m_value)) [[unlikely]] {
|
||||
@@ -96,17 +96,17 @@ public:
|
||||
}
|
||||
|
||||
/* Operators for addition and subtraction. */
|
||||
inline constexpr OverflowSafeInt operator + (const OverflowSafeInt& other) const { OverflowSafeInt result = *this; result += other; return result; }
|
||||
inline constexpr OverflowSafeInt operator + (const int other) const { OverflowSafeInt result = *this; result += (int64_t)other; return result; }
|
||||
inline constexpr OverflowSafeInt operator + (const uint other) const { OverflowSafeInt result = *this; result += (int64_t)other; return result; }
|
||||
inline constexpr OverflowSafeInt operator - (const OverflowSafeInt& other) const { OverflowSafeInt result = *this; result -= other; return result; }
|
||||
inline constexpr OverflowSafeInt operator - (const int other) const { OverflowSafeInt result = *this; result -= (int64_t)other; return result; }
|
||||
inline constexpr OverflowSafeInt operator - (const uint other) const { OverflowSafeInt result = *this; result -= (int64_t)other; return result; }
|
||||
constexpr OverflowSafeInt operator + (const OverflowSafeInt& other) const { OverflowSafeInt result = *this; result += other; return result; }
|
||||
constexpr OverflowSafeInt operator + (const int other) const { OverflowSafeInt result = *this; result += (int64_t)other; return result; }
|
||||
constexpr OverflowSafeInt operator + (const uint other) const { OverflowSafeInt result = *this; result += (int64_t)other; return result; }
|
||||
constexpr OverflowSafeInt operator - (const OverflowSafeInt& other) const { OverflowSafeInt result = *this; result -= other; return result; }
|
||||
constexpr OverflowSafeInt operator - (const int other) const { OverflowSafeInt result = *this; result -= (int64_t)other; return result; }
|
||||
constexpr OverflowSafeInt operator - (const uint other) const { OverflowSafeInt result = *this; result -= (int64_t)other; return result; }
|
||||
|
||||
inline constexpr OverflowSafeInt& operator ++ () { return *this += 1; }
|
||||
inline constexpr OverflowSafeInt& operator -- () { return *this += -1; }
|
||||
inline constexpr OverflowSafeInt operator ++ (int) { OverflowSafeInt org = *this; *this += 1; return org; }
|
||||
inline constexpr OverflowSafeInt operator -- (int) { OverflowSafeInt org = *this; *this += -1; return org; }
|
||||
constexpr OverflowSafeInt& operator ++ () { return *this += 1; }
|
||||
constexpr OverflowSafeInt& operator -- () { return *this += -1; }
|
||||
constexpr OverflowSafeInt operator ++ (int) { OverflowSafeInt org = *this; *this += 1; return org; }
|
||||
constexpr OverflowSafeInt operator -- (int) { OverflowSafeInt org = *this; *this += -1; return org; }
|
||||
|
||||
/**
|
||||
* Safe implementation of multiplication.
|
||||
@@ -115,7 +115,7 @@ public:
|
||||
* @note when the multiplication would yield more than T_MAX (or less than T_MIN),
|
||||
* it will be T_MAX (respectively T_MIN).
|
||||
*/
|
||||
inline constexpr OverflowSafeInt& operator *= (const int factor)
|
||||
constexpr OverflowSafeInt& operator *= (const int factor)
|
||||
{
|
||||
#ifdef HAS_OVERFLOW_BUILTINS
|
||||
const bool is_result_positive = (this->m_value < 0) == (factor < 0); // -ve * -ve == +ve
|
||||
@@ -141,68 +141,68 @@ public:
|
||||
}
|
||||
|
||||
/* Operators for multiplication. */
|
||||
inline constexpr OverflowSafeInt operator * (const int64_t factor) const { OverflowSafeInt result = *this; result *= factor; return result; }
|
||||
inline constexpr OverflowSafeInt operator * (const int factor) const { OverflowSafeInt result = *this; result *= (int64_t)factor; return result; }
|
||||
inline constexpr OverflowSafeInt operator * (const uint factor) const { OverflowSafeInt result = *this; result *= (int64_t)factor; return result; }
|
||||
inline constexpr OverflowSafeInt operator * (const uint16_t factor) const { OverflowSafeInt result = *this; result *= (int64_t)factor; return result; }
|
||||
inline constexpr OverflowSafeInt operator * (const uint8_t factor) const { OverflowSafeInt result = *this; result *= (int64_t)factor; return result; }
|
||||
constexpr OverflowSafeInt operator * (const int64_t factor) const { OverflowSafeInt result = *this; result *= factor; return result; }
|
||||
constexpr OverflowSafeInt operator * (const int factor) const { OverflowSafeInt result = *this; result *= (int64_t)factor; return result; }
|
||||
constexpr OverflowSafeInt operator * (const uint factor) const { OverflowSafeInt result = *this; result *= (int64_t)factor; return result; }
|
||||
constexpr OverflowSafeInt operator * (const uint16_t factor) const { OverflowSafeInt result = *this; result *= (int64_t)factor; return result; }
|
||||
constexpr OverflowSafeInt operator * (const uint8_t factor) const { OverflowSafeInt result = *this; result *= (int64_t)factor; return result; }
|
||||
|
||||
/* Operators for division. */
|
||||
inline constexpr OverflowSafeInt& operator /= (const int64_t divisor) { this->m_value /= divisor; return *this; }
|
||||
inline constexpr OverflowSafeInt operator / (const OverflowSafeInt& divisor) const { OverflowSafeInt result = *this; result /= divisor.m_value; return result; }
|
||||
inline constexpr OverflowSafeInt operator / (const int divisor) const { OverflowSafeInt result = *this; result /= divisor; return result; }
|
||||
inline constexpr OverflowSafeInt operator / (const uint divisor) const { OverflowSafeInt result = *this; result /= (int)divisor; return result; }
|
||||
constexpr OverflowSafeInt& operator /= (const int64_t divisor) { this->m_value /= divisor; return *this; }
|
||||
constexpr OverflowSafeInt operator / (const OverflowSafeInt& divisor) const { OverflowSafeInt result = *this; result /= divisor.m_value; return result; }
|
||||
constexpr OverflowSafeInt operator / (const int divisor) const { OverflowSafeInt result = *this; result /= divisor; return result; }
|
||||
constexpr OverflowSafeInt operator / (const uint divisor) const { OverflowSafeInt result = *this; result /= (int)divisor; return result; }
|
||||
|
||||
/* Operators for modulo */
|
||||
inline constexpr OverflowSafeInt& operator %= (const int divisor) { this->m_value %= divisor; return *this; }
|
||||
inline constexpr OverflowSafeInt operator % (const int divisor) const { OverflowSafeInt result = *this; result %= divisor; return result; }
|
||||
constexpr OverflowSafeInt& operator %= (const int divisor) { this->m_value %= divisor; return *this; }
|
||||
constexpr OverflowSafeInt operator % (const int divisor) const { OverflowSafeInt result = *this; result %= divisor; return result; }
|
||||
|
||||
/* Operators for shifting. */
|
||||
inline constexpr OverflowSafeInt& operator <<= (const int shift) { this->m_value <<= shift; return *this; }
|
||||
inline constexpr OverflowSafeInt operator << (const int shift) const { OverflowSafeInt result = *this; result <<= shift; return result; }
|
||||
inline constexpr OverflowSafeInt& operator >>= (const int shift) { this->m_value >>= shift; return *this; }
|
||||
inline constexpr OverflowSafeInt operator >> (const int shift) const { OverflowSafeInt result = *this; result >>= shift; return result; }
|
||||
constexpr OverflowSafeInt& operator <<= (const int shift) { this->m_value <<= shift; return *this; }
|
||||
constexpr OverflowSafeInt operator << (const int shift) const { OverflowSafeInt result = *this; result <<= shift; return result; }
|
||||
constexpr OverflowSafeInt& operator >>= (const int shift) { this->m_value >>= shift; return *this; }
|
||||
constexpr OverflowSafeInt operator >> (const int shift) const { OverflowSafeInt result = *this; result >>= shift; return result; }
|
||||
|
||||
/* Operators for (in)equality when comparing overflow safe ints. */
|
||||
inline constexpr bool operator == (const OverflowSafeInt& other) const { return this->m_value == other.m_value; }
|
||||
inline constexpr auto operator <=>(const OverflowSafeInt& other) const { return this->m_value <=> other.m_value; }
|
||||
constexpr bool operator == (const OverflowSafeInt& other) const { return this->m_value == other.m_value; }
|
||||
constexpr auto operator <=>(const OverflowSafeInt& other) const { return this->m_value <=> other.m_value; }
|
||||
|
||||
/* Operators for (in)equality when comparing non-overflow safe ints. */
|
||||
inline constexpr bool operator == (const int other) const { return this->m_value == other; }
|
||||
inline constexpr auto operator <=>(const int other) const { return this->m_value <=> other; }
|
||||
constexpr bool operator == (const int other) const { return this->m_value == other; }
|
||||
constexpr auto operator <=>(const int other) const { return this->m_value <=> other; }
|
||||
|
||||
inline constexpr operator T () const { return this->m_value; }
|
||||
constexpr operator T () const { return this->m_value; }
|
||||
|
||||
static inline constexpr OverflowSafeInt<T> max() { return T_MAX; }
|
||||
static inline constexpr OverflowSafeInt<T> min() { return T_MIN; }
|
||||
static constexpr OverflowSafeInt<T> max() { return T_MAX; }
|
||||
static constexpr OverflowSafeInt<T> min() { return T_MIN; }
|
||||
|
||||
BaseType base() const noexcept { return this->m_value; }
|
||||
};
|
||||
|
||||
|
||||
/* Sometimes we got int64_t operator OverflowSafeInt instead of vice versa. Handle that properly. */
|
||||
template <class T> inline constexpr OverflowSafeInt<T> operator + (const int64_t a, const OverflowSafeInt<T> b) { return b + a; }
|
||||
template <class T> inline constexpr OverflowSafeInt<T> operator - (const int64_t a, const OverflowSafeInt<T> b) { return -b + a; }
|
||||
template <class T> inline constexpr OverflowSafeInt<T> operator * (const int64_t a, const OverflowSafeInt<T> b) { return b * a; }
|
||||
template <class T> inline constexpr OverflowSafeInt<T> operator / (const int64_t a, const OverflowSafeInt<T> b) { return (OverflowSafeInt<T>)a / (int)b; }
|
||||
template <class T> constexpr OverflowSafeInt<T> operator + (const int64_t a, const OverflowSafeInt<T> b) { return b + a; }
|
||||
template <class T> constexpr OverflowSafeInt<T> operator - (const int64_t a, const OverflowSafeInt<T> b) { return -b + a; }
|
||||
template <class T> constexpr OverflowSafeInt<T> operator * (const int64_t a, const OverflowSafeInt<T> b) { return b * a; }
|
||||
template <class T> constexpr OverflowSafeInt<T> operator / (const int64_t a, const OverflowSafeInt<T> b) { return (OverflowSafeInt<T>)a / (int)b; }
|
||||
|
||||
/* Sometimes we got int operator OverflowSafeInt instead of vice versa. Handle that properly. */
|
||||
template <class T> inline constexpr OverflowSafeInt<T> operator + (const int a, const OverflowSafeInt<T> b) { return b + a; }
|
||||
template <class T> inline constexpr OverflowSafeInt<T> operator - (const int a, const OverflowSafeInt<T> b) { return -b + a; }
|
||||
template <class T> inline constexpr OverflowSafeInt<T> operator * (const int a, const OverflowSafeInt<T> b) { return b * a; }
|
||||
template <class T> inline constexpr OverflowSafeInt<T> operator / (const int a, const OverflowSafeInt<T> b) { return (OverflowSafeInt<T>)a / (int)b; }
|
||||
template <class T> constexpr OverflowSafeInt<T> operator + (const int a, const OverflowSafeInt<T> b) { return b + a; }
|
||||
template <class T> constexpr OverflowSafeInt<T> operator - (const int a, const OverflowSafeInt<T> b) { return -b + a; }
|
||||
template <class T> constexpr OverflowSafeInt<T> operator * (const int a, const OverflowSafeInt<T> b) { return b * a; }
|
||||
template <class T> constexpr OverflowSafeInt<T> operator / (const int a, const OverflowSafeInt<T> b) { return (OverflowSafeInt<T>)a / (int)b; }
|
||||
|
||||
/* Sometimes we got uint operator OverflowSafeInt instead of vice versa. Handle that properly. */
|
||||
template <class T> inline constexpr OverflowSafeInt<T> operator + (const uint a, const OverflowSafeInt<T> b) { return b + a; }
|
||||
template <class T> inline constexpr OverflowSafeInt<T> operator - (const uint a, const OverflowSafeInt<T> b) { return -b + a; }
|
||||
template <class T> inline constexpr OverflowSafeInt<T> operator * (const uint a, const OverflowSafeInt<T> b) { return b * a; }
|
||||
template <class T> inline constexpr OverflowSafeInt<T> operator / (const uint a, const OverflowSafeInt<T> b) { return (OverflowSafeInt<T>)a / (int)b; }
|
||||
template <class T> constexpr OverflowSafeInt<T> operator + (const uint a, const OverflowSafeInt<T> b) { return b + a; }
|
||||
template <class T> constexpr OverflowSafeInt<T> operator - (const uint a, const OverflowSafeInt<T> b) { return -b + a; }
|
||||
template <class T> constexpr OverflowSafeInt<T> operator * (const uint a, const OverflowSafeInt<T> b) { return b * a; }
|
||||
template <class T> constexpr OverflowSafeInt<T> operator / (const uint a, const OverflowSafeInt<T> b) { return (OverflowSafeInt<T>)a / (int)b; }
|
||||
|
||||
/* Sometimes we got byte operator OverflowSafeInt instead of vice versa. Handle that properly. */
|
||||
template <class T> inline constexpr OverflowSafeInt<T> operator + (const uint8_t a, const OverflowSafeInt<T> b) { return b + (uint)a; }
|
||||
template <class T> inline constexpr OverflowSafeInt<T> operator - (const uint8_t a, const OverflowSafeInt<T> b) { return -b + (uint)a; }
|
||||
template <class T> inline constexpr OverflowSafeInt<T> operator * (const uint8_t a, const OverflowSafeInt<T> b) { return b * (uint)a; }
|
||||
template <class T> inline constexpr OverflowSafeInt<T> operator / (const uint8_t a, const OverflowSafeInt<T> b) { return (OverflowSafeInt<T>)a / (int)b; }
|
||||
template <class T> constexpr OverflowSafeInt<T> operator + (const uint8_t a, const OverflowSafeInt<T> b) { return b + (uint)a; }
|
||||
template <class T> constexpr OverflowSafeInt<T> operator - (const uint8_t a, const OverflowSafeInt<T> b) { return -b + (uint)a; }
|
||||
template <class T> constexpr OverflowSafeInt<T> operator * (const uint8_t a, const OverflowSafeInt<T> b) { return b * (uint)a; }
|
||||
template <class T> constexpr OverflowSafeInt<T> operator / (const uint8_t a, const OverflowSafeInt<T> b) { return (OverflowSafeInt<T>)a / (int)b; }
|
||||
|
||||
typedef OverflowSafeInt<int64_t> OverflowSafeInt64;
|
||||
typedef OverflowSafeInt<int32_t> OverflowSafeInt32;
|
||||
|
||||
@@ -72,7 +72,7 @@ void SetRandomSeed(uint32_t seed)
|
||||
uint32_t Random(const std::source_location location)
|
||||
{
|
||||
if (_networking && (!_network_server || (NetworkClientSocket::IsValidID(0) && NetworkClientSocket::Get(0)->status != NetworkClientSocket::ClientStatus::Inactive))) {
|
||||
Debug(random, 0, "{:08x}; {:02x}; {:04x}; {:02x}; {}:{}", TimerGameEconomy::date, TimerGameEconomy::date_fract, _frame_counter, _current_company, location.file_name(), location.line());
|
||||
Debug(Facility::Random, Severity::Critical, "{:08x}; {:02x}; {:04x}; {:02x}; {}:{}", TimerGameEconomy::date, TimerGameEconomy::date_fract, _frame_counter, _current_company, location.file_name(), location.line());
|
||||
}
|
||||
|
||||
return _random.Next();
|
||||
@@ -120,9 +120,9 @@ void RandomBytesWithFallback(std::span<uint8_t> buf)
|
||||
# warning "No cryptographically-strong random generator available; using a fallback instead"
|
||||
#endif
|
||||
|
||||
static bool warned_once = false;
|
||||
Debug(misc, warned_once ? 1 : 0, "Cryptographically-strong random generator unavailable; using fallback");
|
||||
warned_once = true;
|
||||
static Severity severity = Severity::Critical;
|
||||
Debug(Facility::Misc, severity, "Cryptographically-strong random generator unavailable; using fallback");
|
||||
severity = Severity::Error;
|
||||
|
||||
for (uint i = 0; i < buf.size(); i++) {
|
||||
buf[i] = static_cast<uint8_t>(InteractiveRandom());
|
||||
|
||||
@@ -91,6 +91,13 @@ inline uint32_t RandomRange(uint32_t limit, const std::source_location location
|
||||
return ScaleToLimit(Random(location), limit);
|
||||
}
|
||||
|
||||
/** @copydoc RandomRange */
|
||||
template <typename T> requires std::is_enum_v<T>
|
||||
inline T RandomRange(T limit, const std::source_location location = std::source_location::current())
|
||||
{
|
||||
return static_cast<T>(RandomRange(to_underlying(limit), location));
|
||||
}
|
||||
|
||||
inline uint32_t InteractiveRandom()
|
||||
{
|
||||
return _interactive_random.Next();
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
#if defined(STRGEN) || defined(SETTINGSGEN)
|
||||
FatalErrorI(std::move(msg));
|
||||
#else
|
||||
DebugPrint("misc", 0, std::move(msg));
|
||||
DebugPrint(Facility::Misc, Severity::Critical, std::move(msg));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "core/bitmath_func.hpp"
|
||||
#include "cpu.h"
|
||||
|
||||
#include "safeguards.h"
|
||||
|
||||
@@ -72,7 +73,6 @@ static CPUIDArray CPUID([[maybe_unused]] int type)
|
||||
info[3] |= (1<<26); /* HasCPUIDFlag(1, 3, 26) */
|
||||
# endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return info;
|
||||
}
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
#include "music/music_driver.hpp"
|
||||
#include "sound/sound_driver.hpp"
|
||||
#include "video/video_driver.hpp"
|
||||
#include "saveload/saveload.h"
|
||||
#include "saveload/saveload_func.h"
|
||||
#include "screenshot.h"
|
||||
#include "network/network_survey.h"
|
||||
#include "news_func.h"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user