mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-10 04:31:34 -10:00
Compare commits
378
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
05f2db381a | ||
|
|
6038076bf0 | ||
|
|
40c8cbbb25 | ||
|
|
bd7429c353 | ||
|
|
faf130adb3 | ||
|
|
f7fef072df | ||
|
|
0da6a4a64c | ||
|
|
f542fea96e | ||
|
|
742326e42e | ||
|
|
e25a6517fc | ||
|
|
be0c78dc72 | ||
|
|
ef681affbf | ||
|
|
3a2ac5ab5f | ||
|
|
435676a67d | ||
|
|
4fbe3b7131 | ||
|
|
87a4ae1e41 | ||
|
|
c738941ccf | ||
|
|
5c25bb9bcb | ||
|
|
e0bc6d0ed7 | ||
|
|
ec706a6a87 | ||
|
|
5d0127a764 | ||
|
|
91c15e6f48 | ||
|
|
a9fc7bab8a | ||
|
|
042c85d213 | ||
|
|
bb3d59ecbe | ||
|
|
d1c57391cf | ||
|
|
5986b7143f | ||
|
|
5d447951b4 | ||
|
|
f149c36b44 | ||
|
|
34b6cf74ab | ||
|
|
bc33f90e32 | ||
|
|
bb47531c55 | ||
|
|
aed90493ec | ||
|
|
d54c3e51e3 | ||
|
|
a215bea0d0 | ||
|
|
ec23f6bd0e | ||
|
|
d93d56e1c9 | ||
|
|
d2265325e9 | ||
|
|
2bb22a2153 | ||
|
|
018c22eee1 | ||
|
|
6ef60c67ca | ||
|
|
982e8d7f85 | ||
|
|
8affd53cf6 | ||
|
|
eeaf894b15 | ||
|
|
b546d897ae | ||
|
|
d8aea4ad30 | ||
|
|
829692b7bd | ||
|
|
855935d4eb | ||
|
|
f83efb54c0 | ||
|
|
3ca26587eb | ||
|
|
3e2bb36d4b | ||
|
|
02bd62ff3c | ||
|
|
e1e0239914 | ||
|
|
e621dbe997 | ||
|
|
ea5c328c13 | ||
|
|
8c0bc25303 | ||
|
|
6b0a3b7606 | ||
|
|
9afe76b5d2 | ||
|
|
ad27664ebc | ||
|
|
2fe182a4b1 | ||
|
|
60c2718b91 | ||
|
|
15d9b9b3db | ||
|
|
d00003e199 | ||
|
|
991d0ee2d6 | ||
|
|
3eee74a31c | ||
|
|
941d5f7ec3 | ||
|
|
0cde26dd6e | ||
|
|
7804f7fff5 | ||
|
|
832cec27ad | ||
|
|
31acb115c2 | ||
|
|
f9591b3a92 | ||
|
|
21f92194f1 | ||
|
|
c605451460 | ||
|
|
2acdc65875 | ||
|
|
b7de2fd644 | ||
|
|
a226a81d80 | ||
|
|
eb39532f7c | ||
|
|
1478ace3e0 | ||
|
|
7edc5bf842 | ||
|
|
b8dc7d643d | ||
|
|
883ed32796 | ||
|
|
f3dfc85c0f | ||
|
|
e32ea7b694 | ||
|
|
7ef70f6d4d | ||
|
|
1b1afbf8d7 | ||
|
|
bfdf05469b | ||
|
|
aee48373ab | ||
|
|
a2f1638a99 | ||
|
|
762cf4cb88 | ||
|
|
705287c8d4 | ||
|
|
e2aac31912 | ||
|
|
a9f5a11813 | ||
|
|
b8728ed828 | ||
|
|
de1110650f | ||
|
|
b3295e5a2d | ||
|
|
a6c1b1b04a | ||
|
|
b5fdf52e8c | ||
|
|
c43f5bdd58 | ||
|
|
dc7fc774b8 | ||
|
|
dad16f76c4 | ||
|
|
d10c59f6cc | ||
|
|
3bd2fc9a56 | ||
|
|
fabff58d09 | ||
|
|
2fd3bf091d | ||
|
|
b4442d3423 | ||
|
|
cf4cae7264 | ||
|
|
ebea1b1240 | ||
|
|
54341acb9b | ||
|
|
07fd188064 | ||
|
|
0cbe06884b | ||
|
|
c1d3e5a2ad | ||
|
|
2bcedc34cc | ||
|
|
16892c3e46 | ||
|
|
5c88b75b94 | ||
|
|
987c705bc9 | ||
|
|
b89cbbd530 | ||
|
|
d3383d9d87 | ||
|
|
4f6d9c36a8 | ||
|
|
a36157f582 | ||
|
|
3837455004 | ||
|
|
808f7a88c6 | ||
|
|
79702273d5 | ||
|
|
d06018bcad | ||
|
|
ac87cde80d | ||
|
|
06d9e02c34 | ||
|
|
40233ae05f | ||
|
|
57192065d6 | ||
|
|
d2031a476a | ||
|
|
c60ea2d4a7 | ||
|
|
6843d48358 | ||
|
|
066b251052 | ||
|
|
4596600627 | ||
|
|
ea262f90c0 | ||
|
|
02e84f212a | ||
|
|
a1d92afebf | ||
|
|
a20f3ca030 | ||
|
|
e132fcf74c | ||
|
|
7a4df25fc5 | ||
|
|
08dfcc8b74 | ||
|
|
0def45b381 | ||
|
|
be6a2b9196 | ||
|
|
f7413be1d8 | ||
|
|
02233fc439 | ||
|
|
febd8cd2ad | ||
|
|
bf7125724d | ||
|
|
efce98db47 | ||
|
|
45abdefc07 | ||
|
|
73c612034b | ||
|
|
1ae9aaab21 | ||
|
|
3a46ed66ba | ||
|
|
f98806b034 | ||
|
|
1812efa209 | ||
|
|
2966757e62 | ||
|
|
bc3aad374e | ||
|
|
dcfea6f141 | ||
|
|
c5d192524e | ||
|
|
7a47cc0521 | ||
|
|
a33cc0f6c4 | ||
|
|
af4ec4facc | ||
|
|
d897643217 | ||
|
|
5688ba8637 | ||
|
|
6631975e45 | ||
|
|
fa2b135bb1 | ||
|
|
1ce9d46822 | ||
|
|
7f4d78f44a | ||
|
|
10f484a504 | ||
|
|
f0c8c9ad74 | ||
|
|
79579eda94 | ||
|
|
f7b9896294 | ||
|
|
be8ec82649 | ||
|
|
b72b7688f9 | ||
|
|
c2e01864d5 | ||
|
|
7a4d4466fd | ||
|
|
ec75cac4d9 | ||
|
|
b6c0e8b562 | ||
|
|
8d0570846b | ||
|
|
93d0624b3e | ||
|
|
563445466e | ||
|
|
b7e9d4c9cb | ||
|
|
348fb5ffb4 | ||
|
|
d754c2cb50 | ||
|
|
b760c5dec8 | ||
|
|
9c9b06a1b1 | ||
|
|
30da49be81 | ||
|
|
c2d0eafc36 | ||
|
|
e3c7f81412 | ||
|
|
2b155c7a30 | ||
|
|
df69993a84 | ||
|
|
3fb5bf1f5f | ||
|
|
6823e24350 | ||
|
|
305a7f6630 | ||
|
|
14a98e1470 | ||
|
|
4ba6191e0c | ||
|
|
cb5bf05424 | ||
|
|
b4f633767e | ||
|
|
15db3b17bc | ||
|
|
ba2c37a1fe | ||
|
|
aa997dd9ed | ||
|
|
6dbfba2c9f | ||
|
|
9748de5ec1 | ||
|
|
a0a523223c | ||
|
|
0765c7be95 | ||
|
|
73f8e57961 | ||
|
|
743d8dd666 | ||
|
|
8fbf22a055 | ||
|
|
7b410b2116 | ||
|
|
8fed4437ee | ||
|
|
ad25418f92 | ||
|
|
5972457ad5 | ||
|
|
35876bc17e | ||
|
|
46fa212db6 | ||
|
|
d0d65cd30c | ||
|
|
cb0e9ce601 | ||
|
|
13bc0362c8 | ||
|
|
5749b856df | ||
|
|
f67814aaae | ||
|
|
24daea79f3 | ||
|
|
0f013f920b | ||
|
|
0811c7037b | ||
|
|
f13a5b3736 | ||
|
|
04a5778235 | ||
|
|
5a941c1d59 | ||
|
|
d0c3c7db21 | ||
|
|
be678c2f54 | ||
|
|
9586f21780 | ||
|
|
ed5a5861f7 | ||
|
|
16180306ad | ||
|
|
865045a231 | ||
|
|
0b54c741a6 | ||
|
|
baa34f1ffe | ||
|
|
89b33ebbc5 | ||
|
|
53e6edf8bb | ||
|
|
0220ad0563 | ||
|
|
910521bdfe | ||
|
|
7003e5caa2 | ||
|
|
8efe146300 | ||
|
|
a14fb35713 | ||
|
|
2d0dc7798d | ||
|
|
8242e3b94b | ||
|
|
16cb6b3f2f | ||
|
|
8c9be400a6 | ||
|
|
7974a682ef | ||
|
|
41af098d19 | ||
|
|
4c95370f74 | ||
|
|
a6730a997c | ||
|
|
c5b84d9406 | ||
|
|
d2f5a12d5f | ||
|
|
6f6e839bbf | ||
|
|
065524fd4b | ||
|
|
c84cb7ab64 | ||
|
|
587ed4e41f | ||
|
|
8b8daece46 | ||
|
|
d73d46feb2 | ||
|
|
a881b339cc | ||
|
|
1f90be0a86 | ||
|
|
4ce02ce291 | ||
|
|
7d83ece711 | ||
|
|
9ee1a6eb23 | ||
|
|
f258554304 | ||
|
|
994048eb24 | ||
|
|
0af3197a90 | ||
|
|
e5824b41bb | ||
|
|
679c3606c5 | ||
|
|
acbab034cc | ||
|
|
45306da4fe | ||
|
|
f09c7b3ba5 | ||
|
|
964f495238 | ||
|
|
865f7e725c | ||
|
|
6a550a6701 | ||
|
|
ad2531efcc | ||
|
|
8af06b9e78 | ||
|
|
b6eef2e8f2 | ||
|
|
344e231058 | ||
|
|
2feeb34629 | ||
|
|
9d28ba568c | ||
|
|
1b6ed75d73 | ||
|
|
4cf7ab3474 | ||
|
|
bd4b9cb0d7 | ||
|
|
926e10584c | ||
|
|
defab61664 | ||
|
|
7dc971a6f2 | ||
|
|
e0a6ca9abd | ||
|
|
210a9a8309 | ||
|
|
613fad21c9 | ||
|
|
91497d5056 | ||
|
|
6b3e50dade | ||
|
|
e796a4fe00 | ||
|
|
03f01604d9 | ||
|
|
1547526057 | ||
|
|
7602b88756 | ||
|
|
4812ff529d | ||
|
|
fe42c7bdff | ||
|
|
f706d6c0a0 | ||
|
|
16b9225533 | ||
|
|
9a7500de36 | ||
|
|
64d9b6fb74 | ||
|
|
b40f5a15b2 | ||
|
|
52a5c356cf | ||
|
|
e71dba4207 | ||
|
|
3b42ee42ca | ||
|
|
b270c44ede | ||
|
|
6cf6f8a6fe | ||
|
|
c273496c1e | ||
|
|
8933aaff38 | ||
|
|
a3de0db735 | ||
|
|
0dcb60f805 | ||
|
|
1bc7732b6e | ||
|
|
2a64abfe92 | ||
|
|
d1e81be2aa | ||
|
|
e285641ac6 | ||
|
|
d3b1ad4328 | ||
|
|
914f0e13e3 | ||
|
|
df68da3dd6 | ||
|
|
0219e65b00 | ||
|
|
cc171a6344 | ||
|
|
7d066a1c45 | ||
|
|
6677fcabae | ||
|
|
171d36bf7f | ||
|
|
9018ddf0d5 | ||
|
|
d847236dd2 | ||
|
|
bb6b010487 | ||
|
|
0ee3d099ab | ||
|
|
9aa48579b0 | ||
|
|
bb28d0b859 | ||
|
|
2ef3a935e4 | ||
|
|
233fa38890 | ||
|
|
e91d6ed17b | ||
|
|
f6c86464aa | ||
|
|
dd0af0e07c | ||
|
|
24031db712 | ||
|
|
d82b02a54a | ||
|
|
a21876127d | ||
|
|
f64de84e7c | ||
|
|
feadc0bd69 | ||
|
|
1252d794db | ||
|
|
58fcbde152 | ||
|
|
b3970798e1 | ||
|
|
da34e25bc3 | ||
|
|
7fc75c0d6c | ||
|
|
859978fd84 | ||
|
|
7781d9fcda | ||
|
|
03e876f65b | ||
|
|
9480869e0a | ||
|
|
481e82303c | ||
|
|
689ac56bc8 | ||
|
|
c80f787d34 | ||
|
|
c5469982c8 | ||
|
|
db64a212d6 | ||
|
|
0a07b7e0ad | ||
|
|
833d181700 | ||
|
|
dfc716d91a | ||
|
|
8dd6a27418 | ||
|
|
691ae8752e | ||
|
|
14b4fd3465 | ||
|
|
fc6a1402c3 | ||
|
|
275f96d80c | ||
|
|
850d706df2 | ||
|
|
b06c8e72e1 | ||
|
|
b1fd9ffffb | ||
|
|
e2c264cec4 | ||
|
|
3f889137d7 | ||
|
|
19f1e6b4ee | ||
|
|
7e692ebca6 | ||
|
|
0067a57f8f | ||
|
|
e028162dc2 | ||
|
|
9b26439dd3 | ||
|
|
1431270287 | ||
|
|
06e74fa976 | ||
|
|
318fde51d7 | ||
|
|
15daaf2633 | ||
|
|
d253302fc9 | ||
|
|
560eb31e4f | ||
|
|
493df37287 | ||
|
|
32298b89fd | ||
|
|
d6ee515873 | ||
|
|
bc09f0672b | ||
|
|
17d36156cb | ||
|
|
99450fa643 |
No files matched your search
@@ -15,7 +15,7 @@ jobs:
|
||||
configuration: [FastDebug, Release]
|
||||
name: Linux
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-8a6bbbe
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-3d30dc5
|
||||
steps:
|
||||
# - name: Cache Qt
|
||||
# id: cache-qt-lin
|
||||
@@ -31,11 +31,6 @@ jobs:
|
||||
# cached: ${{ steps.cache-qt-lin.outputs.cache-hit }}
|
||||
# setup-python: 'false'
|
||||
# aqtversion: ==1.1.3
|
||||
# seriously, what the fuck why do i have to do this
|
||||
- name: Add curl to the container
|
||||
run: |
|
||||
apt-get update -y
|
||||
apt -y install curl jq
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
with:
|
||||
@@ -292,13 +287,15 @@ jobs:
|
||||
XDG_RUNTIME_DIR: /root
|
||||
run: $GITHUB_WORKSPACE/ci/linux/run_tests.sh
|
||||
- name: Package build result
|
||||
working-directory: ./build
|
||||
run: cd bin && tar -cvzf macos-build.tar *.app
|
||||
working-directory: ./build/bin
|
||||
# Use GNU tar here (part of runner image) to avoid weird corruption bug with bsdtar
|
||||
# Ref: https://github.com/actions/runner-images/issues/2619
|
||||
run: gtar -cvzf macos-build-${{ matrix.configuration }}.tgz *.app
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: mac-${{ matrix.configuration }}
|
||||
path: ${{ github.workspace }}/build/bin/macos-build.tar
|
||||
path: ${{ github.workspace }}/build/bin/macos-build-${{ matrix.configuration }}.tgz
|
||||
mac_zip:
|
||||
name: Build Mac distribution zip
|
||||
needs: build_mac
|
||||
@@ -321,6 +318,11 @@ jobs:
|
||||
with:
|
||||
name: mac-FastDebug
|
||||
path: builds
|
||||
- name: Unpack builds
|
||||
working-directory: ./builds
|
||||
run: |
|
||||
tar -xvzf macos-build-Release.tgz
|
||||
tar -xvzf macos-build-FastDebug.tgz
|
||||
- name: Create Distribution package
|
||||
working-directory: ./builds
|
||||
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Mac
|
||||
|
||||
@@ -44,7 +44,7 @@ jobs:
|
||||
name: Linux
|
||||
needs: create_release # Don't run this job until create_release is done and successful
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-8a6bbbe
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-3d30dc5
|
||||
steps:
|
||||
# - name: Cache Qt
|
||||
# id: cache-qt-lin
|
||||
@@ -87,15 +87,12 @@ jobs:
|
||||
# cached: ${{ steps.cache-qt-lin.outputs.cache-hit }}
|
||||
# setup-python: 'false'
|
||||
# aqtversion: ==1.1.3
|
||||
- name: Add curl to the container
|
||||
run: |
|
||||
apt-get update -y
|
||||
apt -y install curl jq
|
||||
- uses: actions/checkout@v1
|
||||
# checks-out your repository under $GITHUB_WORKSPACE, so your workflow can access it.
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true # `true` to checkout submodules, `recursive` to recursively checkout submodules
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected]
|
||||
with:
|
||||
@@ -149,6 +146,7 @@ jobs:
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: '0' # value 0 to fetch all history and tags for all branches
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Download Release builds
|
||||
# Grab the release builds
|
||||
uses: actions/download-artifact@v2
|
||||
@@ -195,6 +193,7 @@ jobs:
|
||||
name: Checkout
|
||||
with:
|
||||
submodules: true
|
||||
ref: '${{ github.ref }}'
|
||||
# - name: Cache Qt
|
||||
# # Cache Qt
|
||||
# id: cache-qt-win
|
||||
@@ -289,7 +288,7 @@ jobs:
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: '0'
|
||||
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Download Release builds
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
@@ -361,6 +360,7 @@ jobs:
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: 0
|
||||
ref: '${{ github.ref }}'
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected]
|
||||
with:
|
||||
@@ -384,13 +384,15 @@ jobs:
|
||||
XDG_RUNTIME_DIR: /root
|
||||
run: $GITHUB_WORKSPACE/ci/linux/run_tests.sh
|
||||
- name: Package build result
|
||||
working-directory: ./build
|
||||
run: cd bin && tar -cvzf macos-build.tar *.app
|
||||
working-directory: ./build/bin
|
||||
# Use GNU tar here (part of runner image) to avoid weird corruption bug with bsdtar
|
||||
# Ref: https://github.com/actions/runner-images/issues/2619
|
||||
run: gtar -cvzf macos-build-${{ matrix.configuration }}.tgz *.app
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: mac-${{ matrix.configuration }}
|
||||
path: ${{ github.workspace }}/build/bin/macos-build.tar
|
||||
path: ${{ github.workspace }}/build/bin/macos-build-${{ matrix.configuration }}.tgz
|
||||
mac_zip:
|
||||
name: Build Mac distribution zip
|
||||
needs: build_mac
|
||||
@@ -413,6 +415,11 @@ jobs:
|
||||
with:
|
||||
name: mac-FastDebug
|
||||
path: builds
|
||||
- name: Unpack builds
|
||||
working-directory: ./builds
|
||||
run: |
|
||||
tar -xvzf macos-build-Release.tgz
|
||||
tar -xvzf macos-build-FastDebug.tgz
|
||||
- name: Create Distribution package
|
||||
id: generate_package
|
||||
working-directory: ./builds
|
||||
|
||||
@@ -20,10 +20,6 @@ jobs:
|
||||
fail-fast: false
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Add curl to the container
|
||||
run: |
|
||||
apt-get update -y
|
||||
apt -y install curl jq
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
with:
|
||||
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
configuration: [FastDebug, Release]
|
||||
name: Linux
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-8a6bbbe
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-3d30dc5
|
||||
steps:
|
||||
# - name: Cache Qt
|
||||
# id: cache-qt-lin
|
||||
@@ -31,10 +31,6 @@ jobs:
|
||||
# cached: ${{ steps.cache-qt-lin.outputs.cache-hit }}
|
||||
# setup-python: 'false'
|
||||
# aqtversion: ==1.1.3
|
||||
- name: Add curl to the container
|
||||
run: |
|
||||
apt-get update -y
|
||||
apt -y install curl jq
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
with:
|
||||
@@ -304,13 +300,15 @@ jobs:
|
||||
XDG_RUNTIME_DIR: /root
|
||||
run: $GITHUB_WORKSPACE/ci/linux/run_tests.sh
|
||||
- name: Package build result
|
||||
working-directory: ./build
|
||||
run: cd bin && tar -cvzf macos-build.tar *.app
|
||||
working-directory: ./build/bin
|
||||
# Use GNU tar here (part of runner image) to avoid weird corruption bug with bsdtar
|
||||
# Ref: https://github.com/actions/runner-images/issues/2619
|
||||
run: gtar -cvzf macos-build-${{ matrix.configuration }}.tgz *.app
|
||||
- name: Upload build result
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: mac-${{ matrix.configuration }}
|
||||
path: ${{ github.workspace }}/build/bin/macos-build.tar
|
||||
path: ${{ github.workspace }}/build/bin/macos-build-${{ matrix.configuration }}.tgz
|
||||
mac_zip:
|
||||
name: Build Mac distribution zip
|
||||
needs: build_mac
|
||||
@@ -333,6 +331,11 @@ jobs:
|
||||
with:
|
||||
name: mac-FastDebug
|
||||
path: builds
|
||||
- name: Unpack builds
|
||||
working-directory: ./builds
|
||||
run: |
|
||||
tar -xvzf macos-build-Release.tgz
|
||||
tar -xvzf macos-build-FastDebug.tgz
|
||||
- name: Create Distribution package
|
||||
working-directory: ./builds
|
||||
run: $GITHUB_WORKSPACE/ci/linux/create_dist_pack.sh Mac
|
||||
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
cmake_options: -DFSO_BUILD_WITH_OPENGL=OFF -DFSO_BUILD_WITH_VULKAN=OFF
|
||||
name: Linux
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-8a6bbbe
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-3d30dc5
|
||||
steps:
|
||||
# - name: Cache Qt
|
||||
# id: cache-qt-lin
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
name: Weekly Coverity Scan for Freespace Open
|
||||
# adapted from code by "albert-github" on the doxygen repository
|
||||
# many thanks for figuring this out first so it could be less painful for us!
|
||||
|
||||
# This mode is for testing
|
||||
on: [push, pull_request]
|
||||
|
||||
# In production, push on a specific schedule
|
||||
#on:
|
||||
# schedule:
|
||||
# - cron: "1 0 * * 5" # Run once per a week on Friday morning (midnight UTC, 4 AM EST), to avoid Coverity's submission limits
|
||||
|
||||
env:
|
||||
QT_VERSION: 5.12.9
|
||||
coverity_email: [email protected]
|
||||
coverity_token: ${{ secrets.COVERITY_TOKEN }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build FSO With Coverity Wrapper
|
||||
runs-on: ${{ matrix.config.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
config:
|
||||
- { name: "GCC on ubuntu", os: ubuntu-latest, build_type: "Release" }
|
||||
steps:
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
sudo apt-get install ninja-build
|
||||
sudo apt install cmake libsdl2-dev g++
|
||||
sudo apt-get install libopenal-dev
|
||||
sudo apt-get install -y libudev-dev
|
||||
sudo apt-get install doxygen
|
||||
sudo apt install graphviz
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive # `true` to checkout submodules, `recursive` to recursively checkout submodules
|
||||
|
||||
# pipe results of wget to a log file because it's very verbose and rarely fails
|
||||
- name: Install Coverity
|
||||
run: |
|
||||
wget -o wgetlog.txt -q https://scan.coverity.com/download/cxx/linux64 --post-data "token=${{ env.coverity_token }}&project=scp-fs2open/fs2open.github.com" -O coverity_tool.tgz
|
||||
mkdir cov-scan
|
||||
tar ax -f coverity_tool.tgz --strip-components=1 -C cov-scan
|
||||
|
||||
- name: Setup Environment
|
||||
run: |
|
||||
echo "$(pwd)/cov-scan/bin" >> $GITHUB_PATH
|
||||
echo "NPROC=$(getconf _NPROCESSORS_ONLN)" >> $GITHUB_ENV
|
||||
|
||||
- name: Prepare Vulkan SDK
|
||||
uses: humbletim/[email protected]
|
||||
with:
|
||||
vulkan-query-version: 1.3.204.0
|
||||
vulkan-components: Vulkan-Headers, Vulkan-Loader
|
||||
vulkan-use-cache: true
|
||||
|
||||
- name: Configure CMake for FSO
|
||||
env:
|
||||
CONFIGURATION: Release
|
||||
compiler: gcc-5
|
||||
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
|
||||
|
||||
- name: Build FSO with Coverity Wrapper
|
||||
working-directory: ./build
|
||||
env:
|
||||
CONFIGURATION: Release
|
||||
run: cov-build --dir cov-int ninja -k 20 all
|
||||
|
||||
- name: Compress Results
|
||||
working-directory: ./build
|
||||
run: tar zcf cov-scan.tgz cov-int
|
||||
|
||||
#Comment this out when testing to keep from running into upload limits
|
||||
- name: Upload to Coverity
|
||||
run: |
|
||||
cd build
|
||||
curl --form token=${{ env.coverity_token }} --form email=${{ env.coverity_email }} --form [email protected] --form version="$(git rev-parse HEAD)" --form description="Automatic GHA scan" 'https://scan.coverity.com/builds?project=scp-fs2open/fs2open.github.com'
|
||||
@@ -22,7 +22,7 @@ jobs:
|
||||
cmake_options: -DFSO_BUILD_WITH_OPENGL=OFF -DFSO_BUILD_WITH_VULKAN=OFF
|
||||
name: Linux
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-8a6bbbe
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-3d30dc5
|
||||
steps:
|
||||
# - name: Cache Qt
|
||||
# id: cache-qt-lin
|
||||
@@ -38,10 +38,6 @@ jobs:
|
||||
# cached: ${{ steps.cache-qt-lin.outputs.cache-hit }}
|
||||
# setup-python: 'false'
|
||||
# aqtversion: ==1.1.3
|
||||
- name: Add curl to the container
|
||||
run: |
|
||||
apt-get update -y
|
||||
apt -y install curl jq
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout
|
||||
with:
|
||||
@@ -245,4 +241,4 @@ jobs:
|
||||
if: startsWith(matrix.compiler, 'clang-')
|
||||
uses: asarium/clang-tidy-action@v1
|
||||
with:
|
||||
fixesFile: clang-fixes.yaml
|
||||
fixesFile: clang-fixes.yaml
|
||||
@@ -250,6 +250,7 @@ documentation/doxygen/*
|
||||
projects/*
|
||||
/.vs
|
||||
CMakeSettings.json
|
||||
CMakePresets.json
|
||||
|
||||
# Weird files created by Linux
|
||||
.fuse_hidden*
|
||||
|
||||
-175
@@ -1,175 +0,0 @@
|
||||
language: bash
|
||||
sudo: required
|
||||
dist: xenial
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/cmake-3.8
|
||||
- $HOME/.ccache
|
||||
- $HOME/curl_cache
|
||||
addons:
|
||||
apt:
|
||||
packages: &global_deps
|
||||
- ninja-build
|
||||
- libopenal-dev
|
||||
- libreadline6-dev
|
||||
- libpng12-dev
|
||||
- libjpeg62-dev
|
||||
- liblua5.1-0-dev
|
||||
- libjansson-dev
|
||||
- libsdl2-dev
|
||||
- libfreetype6-dev
|
||||
- qt57base
|
||||
coverity_scan:
|
||||
project:
|
||||
name: "scp-fs2open/fs2open.github.com"
|
||||
notification_email: [email protected]
|
||||
build_command: "ci/travis/script.sh"
|
||||
# must match TRAVIS_BRANCH check below
|
||||
branch_pattern: coverity_scan
|
||||
env:
|
||||
global:
|
||||
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
|
||||
# via the "travis encrypt" command using the project repo's public key
|
||||
# also note that fork's don't get access to secure keys
|
||||
# you have to test using a branch in the main repo
|
||||
- secure: "C3wF967ZeliwwP1vC12EMIBOaC568n26Z/cPnwzn317ve59DWH3YSfPZVgvt08GzmaXITGGsJvPB+qxfGoKvQzYE4O1B73q81RpUe5pB3IhF+ThQ91VfQZIRJR5xEGJaLINUlHTTZGX5jxlkVO9wAcauVj/s3b8sQ3dvUZauPvk="
|
||||
# These declarations set INDIEGAMES_USER and INDIEGAMES_PASSWORD for uploading nightly builds to the indiegames server
|
||||
- secure: "lUuRu8XIi8MKNf1ebOfyC4iVEpPyASojJIDWXRo2bNqEF4ILAljXdkVeXeN6H5yKCHD52cxCNTtyePIG/o3p3QEuGSVud9bDS3D7LaQicLETGGrsw3l07U49gF2OKHXGopg0MzBbZUU9QmhoFTAe8t6PV9NDuEayYCheqvTqjZg="
|
||||
- secure: "E/DHLYcPK/hBUqxBYYlUqp5sjgvIqY5A0qRHyQ4bmjsB+WB/Xx71bGCSiF7hk6lTxar1ZI1i5RAXXh9AIvNVaYAIdEOlCP+q3gvwCYuc5naZEKmkxlUCf0oEL4O9Fye93A/3VkFHuBdC1TGPYYf69m4W5r4367wWO9dPRIdWpJA="
|
||||
# These declarations set DATACORDER_USER and DATACORDER_PASSWORD
|
||||
- secure: "dpBH/dDN3bmU/NFlh+2v9isNx9wX0ocoRy+W+kBXRH32sosUGp26REhMqgVRpBNP5oxPBU8ic5bEogxAYWCB+0xUygBbkxAwyMPgoA34s0OXdTCY/ofw14ni8qqV2Ffy7fQJbP/jkMURyiMHx3kBTxNv3YjxKJqLnOuOMlQLpT8="
|
||||
- secure: "tLMRBD1Ufp5iKNwlqPDVbbuczgusaXNoBJyAnPATpJq2YwlkW4j3PqP9rW5vd85+52xam2EOP20w9PoBR5J6FLdiXRu4Lf7yCEhSHFAgowVqQj8QcJpPlyXr90bM4emFGrGqpdxVwxyQ5AFhKwLuEZKsI14GYLN+UMEwpNCMing="
|
||||
deploy:
|
||||
- provider: releases
|
||||
api_key:
|
||||
secure: "q619+eQTe7lv8UVphK4OIzU8Jw84KBbVkuprN2sWIubRcV3IbZr2+WahJoUMt+nyhiy3YjDYtstO2ZgkxupwnZgwGUBVIiD1c4SPuyy+HTjNMOtiVsEUHT2hf+xPAemWpTlK5HcwhMmHAOh6rt6dEj57QOg0gcmGiwD/tCbEriA="
|
||||
skip_cleanup: true
|
||||
file_glob: true
|
||||
file: "/tmp/builds/*"
|
||||
on:
|
||||
condition: '"$RELEASE_BUILD" == true'
|
||||
tags: true
|
||||
|
||||
- provider: script
|
||||
script: bash ci/travis/ftp_deploy.sh
|
||||
on:
|
||||
condition: '"$NIGHTLY_BUILD" == true'
|
||||
tags: true
|
||||
|
||||
- provider: script
|
||||
skip_cleanup: true
|
||||
script: bash ci/travis/ftp_deploy.sh
|
||||
on:
|
||||
condition: $TEST_BUILD = true
|
||||
all_branches: true
|
||||
|
||||
matrix:
|
||||
include:
|
||||
# note that gcc Debug MUST be 1st for Coverity
|
||||
- os: linux
|
||||
env: CONFIGURATION="Debug" CC=gcc-5 CXX=g++-5
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:beineri/opt-qt571-xenial'
|
||||
packages:
|
||||
- *global_deps
|
||||
- g++-5
|
||||
- os: linux
|
||||
env: CONFIGURATION="Debug" CC=gcc-9 CXX=g++-9
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:beineri/opt-qt571-xenial'
|
||||
packages:
|
||||
- g++-9
|
||||
- *global_deps
|
||||
- os: linux
|
||||
env: CONFIGURATION="Debug" CC=clang-9 CXX=clang++-9 CMAKE_OPTIONS="-DCMAKE_EXPORT_COMPILE_COMMANDS=ON"
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:beineri/opt-qt571-xenial'
|
||||
packages:
|
||||
- *global_deps
|
||||
- g++-9
|
||||
script:
|
||||
- ./ci/travis/script.sh
|
||||
- ./ci/travis/clang_tidy.sh
|
||||
- os: osx
|
||||
env: CONFIGURATION="Debug"
|
||||
|
||||
- os: windows
|
||||
env: CONFIGURATION="Debug" CMAKE_TOOLSET=v141 CMAKE_GENERATOR="Visual Studio 15 2017"
|
||||
- os: windows
|
||||
env: CONFIGURATION="Debug" CMAKE_TOOLSET="" CMAKE_GENERATOR="Ninja"
|
||||
|
||||
- os: linux
|
||||
env: CONFIGURATION="Release" CC=gcc-5 CXX=g++-5
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:beineri/opt-qt571-xenial'
|
||||
packages:
|
||||
- *global_deps
|
||||
- g++-5
|
||||
- os: linux
|
||||
env: CONFIGURATION="Release" CC=gcc-9 CXX=g++-9
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:beineri/opt-qt571-xenial'
|
||||
packages:
|
||||
- g++-9
|
||||
- *global_deps
|
||||
- os: linux
|
||||
env: CONFIGURATION="Release" CC=clang-9 CXX=clang++-9 CMAKE_OPTIONS="-DCMAKE_EXPORT_COMPILE_COMMANDS=ON"
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:beineri/opt-qt571-xenial'
|
||||
packages:
|
||||
- *global_deps
|
||||
- g++-9
|
||||
script:
|
||||
- ./ci/travis/script.sh
|
||||
- ./ci/travis/clang_tidy.sh
|
||||
- os: osx
|
||||
env: CONFIGURATION="Release"
|
||||
|
||||
- os: windows
|
||||
env: CONFIGURATION="Release" CMAKE_TOOLSET=v141 CMAKE_GENERATOR="Visual Studio 15 2017"
|
||||
- os: windows
|
||||
env: CONFIGURATION="Release" CMAKE_TOOLSET="" CMAKE_GENERATOR="Ninja"
|
||||
# There is a GCC compiler bug with MinGW that causes compilation failures on Windows at the moment
|
||||
allow_failures:
|
||||
- os: windows
|
||||
env: CONFIGURATION="Debug" CMAKE_TOOLSET="" CMAKE_GENERATOR="Ninja"
|
||||
- os: windows
|
||||
env: CONFIGURATION="Release" CMAKE_TOOLSET="" CMAKE_GENERATOR="Ninja"
|
||||
fast_finish: true
|
||||
|
||||
before_install:
|
||||
# ugly hack; if running a coverity scan abort all except the 1st build
|
||||
# see note re gcc compiler above needing to be 1st
|
||||
# also note that branch_pattern & the TRAVIS_BRANCH check must match
|
||||
# unfortunately COVERITY_SCAN_BRANCH isn't defined until later in the
|
||||
# build process
|
||||
- if ([[ "${TRAVIS_JOB_NUMBER##*.}" != "1" ]] && [[ "${TRAVIS_BRANCH}" == "coverity_scan" ]]); then false ; fi
|
||||
- source "./ci/travis/check_release.sh"
|
||||
- "./ci/travis/before_install.sh"
|
||||
install:
|
||||
- if [ "$TRAVIS_OS_NAME" = "windows" ]; then export PATH="/c/Program Files/CMake/bin":$PATH; fi
|
||||
- "./ci/travis/install.sh"
|
||||
- export PATH=$HOME/cmake-3.6/bin:$PATH
|
||||
before_script:
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then QT_ENV_SCRIPT=$(find /opt -name 'qt*-env.sh'); source $QT_ENV_SCRIPT; fi
|
||||
- "./ci/travis/before_script.sh"
|
||||
script:
|
||||
- if [ "$BUILD_DEPLOYMENT" = true ] ; then ./ci/travis/release.sh ; else ./ci/travis/script.sh ; fi
|
||||
@@ -1,7 +1,5 @@
|
||||
FreeSpace2 *S*ource *C*ode *P*roject
|
||||
==
|
||||
[](https://travis-ci.org/scp-fs2open/fs2open.github.com)
|
||||
[](https://ci.appveyor.com/project/SirKnightly/fs2open-github-com/branch/master)
|
||||
[](https://scan.coverity.com/projects/870)
|
||||
|
||||
Building
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
version: 1.0.0.{build}
|
||||
image: Visual Studio 2015
|
||||
configuration:
|
||||
- Debug
|
||||
- Release
|
||||
clone_depth: 10
|
||||
environment:
|
||||
matrix:
|
||||
- BuildID: 0
|
||||
CMAKE_GENERATOR: Visual Studio 14 2015
|
||||
PlatformToolset: v140
|
||||
QT_DIR: C:\Qt\5.9\msvc2015
|
||||
- BuildID: 1
|
||||
CMAKE_GENERATOR: Visual Studio 14 2015 Win64
|
||||
PlatformToolset: v140
|
||||
QT_DIR: C:\Qt\5.9\msvc2015_64
|
||||
before_build:
|
||||
- git submodule update --init --recursive
|
||||
build_script:
|
||||
- ps: . $Env:APPVEYOR_BUILD_FOLDER/ci/appveyor/build.ps1
|
||||
test_script:
|
||||
- ps: . $Env:APPVEYOR_BUILD_FOLDER/ci/appveyor/test.ps1
|
||||
|
||||
deploy:
|
||||
- provider: GitHub
|
||||
auth_token:
|
||||
secure: h55Scpy+3vmo1Yb7WlSIGA4d9DRnsbzUYc2LYsQdByQHZHbqrqjBpicH0D2FFLEO
|
||||
on:
|
||||
ReleaseBuild: true # deploy on release push only
|
||||
|
||||
- provider: FTP
|
||||
protocol: sftp
|
||||
host: scp.indiegames.us
|
||||
username:
|
||||
secure: SFivQZfatqWHXK1ijYK3GQ==
|
||||
password:
|
||||
secure: q6Zk/412o1ri+NEya1dl1Q==
|
||||
folder: public_html/builds/nightly/$(VersionName)
|
||||
on:
|
||||
NightlyBuild: true # deploy on nightly push only
|
||||
|
||||
- provider: FTP
|
||||
protocol: sftp
|
||||
host: porphyrion.feralhosting.com
|
||||
username:
|
||||
secure: 36+bVD8eJgI0BVbi7TZ4zQ==
|
||||
password:
|
||||
secure: CrzmDVca8AGG08iWPA1gOD4Ge06+wJ3rcBagBGclwYQ=
|
||||
folder: www/datacorder.porphyrion.feralhosting.com/public_html/builds/nightly/$(VersionName)
|
||||
on:
|
||||
NightlyBuild: true # deploy on nightly push only
|
||||
|
||||
- provider: FTP
|
||||
protocol: sftp
|
||||
host: porphyrion.feralhosting.com
|
||||
username:
|
||||
secure: 36+bVD8eJgI0BVbi7TZ4zQ==
|
||||
password:
|
||||
secure: CrzmDVca8AGG08iWPA1gOD4Ge06+wJ3rcBagBGclwYQ=
|
||||
folder: www/datacorder.porphyrion.feralhosting.com/public_html/builds/test/$(VersionName)
|
||||
on:
|
||||
TestBuild: true # deploy on test build push only
|
||||
@@ -1,164 +0,0 @@
|
||||
|
||||
class BuildConfig {
|
||||
[string]$Generator
|
||||
[string]$PackageType
|
||||
[string]$Toolset
|
||||
[string]$SimdType
|
||||
[string]$QtDir
|
||||
[Bool]$SourcePackage
|
||||
}
|
||||
|
||||
$NightlyConfigurations = @(
|
||||
# [BuildConfig]@{
|
||||
# Generator="Visual Studio 14 2015 Win64";
|
||||
# PackageType="Win64";
|
||||
# Toolset="v140";
|
||||
# SimdType="SSE2";
|
||||
# QtDir="C:\Qt\5.9\msvc2015_64";
|
||||
# SourcePackage=$false;
|
||||
# },
|
||||
# [BuildConfig]@{
|
||||
# Generator="Visual Studio 14 2015";
|
||||
# PackageType="Win32";
|
||||
# Toolset="v140";
|
||||
# SimdType="SSE2";
|
||||
# QtDir="C:\Qt\5.9\msvc2015";
|
||||
# SourcePackage=$false;
|
||||
# }
|
||||
)
|
||||
$ReleaseConfigurations = @(
|
||||
# [BuildConfig]@{
|
||||
# Generator="Visual Studio 14 2015";
|
||||
# PackageType="Win32";
|
||||
# Toolset="v140";
|
||||
# SimdType="SSE2";
|
||||
# QtDir="C:\Qt\5.9\msvc2015";
|
||||
# SourcePackage=$true;
|
||||
# }
|
||||
# [BuildConfig]@{
|
||||
# Generator="Visual Studio 14 2015";
|
||||
# PackageType="Win32-AVX";
|
||||
# Toolset="v140";
|
||||
# SimdType="AVX";
|
||||
# QtDir="C:\Qt\5.9\msvc2015";
|
||||
# SourcePackage=$false;
|
||||
# }
|
||||
# [BuildConfig]@{
|
||||
# Generator="Visual Studio 14 2015 Win64";
|
||||
# PackageType="Win64";
|
||||
# Toolset="v140";
|
||||
# SimdType="SSE2";
|
||||
# QtDir="C:\Qt\5.9\msvc2015_64";
|
||||
# SourcePackage=$false;
|
||||
# }
|
||||
# [BuildConfig]@{
|
||||
# Generator="Visual Studio 14 2015 Win64";
|
||||
# PackageType="Win64-AVX";
|
||||
# Toolset="v140";
|
||||
# SimdType="AVX";
|
||||
# QtDir="C:\Qt\5.9\msvc2015_64";
|
||||
# SourcePackage=$false;
|
||||
# }
|
||||
)
|
||||
|
||||
$BuildConfigurations = $null
|
||||
|
||||
# Default values
|
||||
$ReleaseBuild = $false
|
||||
$NightlyBuild = $false
|
||||
$TestBuild = $false
|
||||
|
||||
# Set to true to test either the release or the nightly part of this script
|
||||
$ReleaseTest = $false
|
||||
$NightlyTest = $false
|
||||
$TestBuildTest = $false
|
||||
|
||||
if ($ReleaseTest -Or ([System.Convert]::ToBoolean($env:APPVEYOR_REPO_TAG) -And ("$env:APPVEYOR_REPO_TAG_NAME" -match "^release_(.*)"))) {
|
||||
# Tag matches
|
||||
$ReleaseBuild = $true
|
||||
$PackageName = "fs2_open_$($matches[1])"
|
||||
$BuildConfigurations = $ReleaseConfigurations
|
||||
}
|
||||
|
||||
if ($NightlyTest -Or ([System.Convert]::ToBoolean($env:APPVEYOR_REPO_TAG) -And ("$env:APPVEYOR_REPO_TAG_NAME" -match "^nightly_(.*)"))) {
|
||||
# Tag matches
|
||||
$NightlyBuild = $true
|
||||
$PackageName = "nightly_$($matches[1])"
|
||||
Set-AppveyorBuildVariable 'VersionName' "$($matches[1])"
|
||||
$BuildConfigurations = $NightlyConfigurations
|
||||
}
|
||||
|
||||
if ($TestBuildTest -Or ([System.Convert]::ToInt32($env:APPVEYOR_PULL_REQUEST_NUMBER) -le 0 -And ("$env:APPVEYOR_REPO_BRANCH" -match "^test\/(.*)"))) {
|
||||
# Tag matches
|
||||
$TestBuild = $true
|
||||
$PackageName = "test_$($matches[1])"
|
||||
Set-AppveyorBuildVariable 'VersionName' "$($matches[1])"
|
||||
$BuildConfigurations = $NightlyConfigurations
|
||||
|
||||
# Override the revision string so that the builds are named correctly
|
||||
[System.IO.File]::WriteAllLines("$env:APPVEYOR_BUILD_FOLDER/version_override.cmake", "set(FSO_VERSION_REVISION_STR $env:VersionName)")
|
||||
}
|
||||
|
||||
# Multiply by 2 so that we can add 0 or 1 for debug or release Configs
|
||||
$buildID = [convert]::ToInt32($env:BuildID) * 2
|
||||
if ($Env:Configuration -eq "Release") {
|
||||
$buildID = $buildID + 1
|
||||
}
|
||||
|
||||
$DeployBuild = $false
|
||||
if ($ReleaseBuild -Or $NightlyBuild -Or $TestBuild) {
|
||||
$DeployBuild = $true
|
||||
}
|
||||
|
||||
Set-AppveyorBuildVariable 'ReleaseBuild' "$ReleaseBuild"
|
||||
Set-AppveyorBuildVariable 'NightlyBuild' "$NightlyBuild"
|
||||
Set-AppveyorBuildVariable 'TestBuild' "$TestBuild"
|
||||
|
||||
New-Item build -type directory
|
||||
Set-Location -Path build
|
||||
|
||||
if ($DeployBuild) {
|
||||
# Release build
|
||||
if ($buildID -ge $BuildConfigurations.Length) {
|
||||
# Not needed
|
||||
exit 0
|
||||
}
|
||||
|
||||
$buildConfig = $BuildConfigurations[$buildID]
|
||||
|
||||
if ($buildConfig.SourcePackage -eq $True) {
|
||||
7z a -xr'!.git' "$($PackageName)-source-Win.zip" "$env:APPVEYOR_BUILD_FOLDER"
|
||||
Push-AppveyorArtifact "$($PackageName)-source-Win.zip"
|
||||
}
|
||||
|
||||
cmake -DCMAKE_INSTALL_PREFIX="$env:APPVEYOR_BUILD_FOLDER/../install" -DFSO_USE_SPEECH="ON" `
|
||||
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$($buildConfig.SimdType)" `
|
||||
-DQT5_INSTALL_ROOT="$($buildConfig.QtDir)" -DFSO_BUILD_QTFRED=OFF `
|
||||
-DFSO_INSTALL_DEBUG_FILES="ON" `
|
||||
-G "$($buildConfig.Generator)" -T "$($buildConfig.Toolset)" ..
|
||||
|
||||
$Configs = @("Release", "FastDebug")
|
||||
foreach ($config in $Configs) {
|
||||
cmake --build . --config "$config" --target INSTALL -- /verbosity:minimal
|
||||
if (! ($?)) {
|
||||
Add-AppveyorMessage "A release build failed!"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
7z a -xr'!*.pdb' "$($PackageName)-builds-$($buildConfig.PackageType).zip" "$env:APPVEYOR_BUILD_FOLDER/../install/*"
|
||||
Push-AppveyorArtifact "$($PackageName)-builds-$($buildConfig.PackageType).zip"
|
||||
|
||||
7z a "$($PackageName)-debug-$($buildConfig.PackageType).7z" "$env:APPVEYOR_BUILD_FOLDER/../install/*.pdb"
|
||||
Push-AppveyorArtifact "$($PackageName)-debug-$($buildConfig.PackageType).7z"
|
||||
} else {
|
||||
cmake -DFSO_USE_SPEECH="ON" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="ON" -DFSO_BUILD_TESTS="ON" -DMSVC_SIMD_INSTRUCTIONS=SSE2 `
|
||||
-DFSO_BUILD_QTFRED=OFF -DQT5_INSTALL_ROOT="$env:QT_DIR" -DFSO_BUILD_FRED2="ON" `
|
||||
-G "$Env:CMAKE_GENERATOR" -T "$Env:PlatformToolset" ..
|
||||
|
||||
cmake --build . --config "$Env:CONFIGURATION" -- /verbosity:minimal
|
||||
|
||||
if (! ($?)) {
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
|
||||
if ([System.Convert]::ToBoolean($env:ReleaseBuild) -Or [System.Convert]::ToBoolean($env:NightlyBuild) -Or [System.Convert]::ToBoolean($env:TestBuild)) {
|
||||
# Skip tests for deployment
|
||||
exit 0
|
||||
} else {
|
||||
write "Running unit tests..."
|
||||
# Run unit tests
|
||||
&"$pwd\bin\$Env:CONFIGURATION\unittests.exe" --gtest_shuffle 2>&1
|
||||
|
||||
if (! ($?)) {
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ if [ "$RUNNER_OS" = "macOS" ]; then
|
||||
PLATFORM_CMAKE_OPTIONS="-DFSO_BUILD_WITH_VULKAN=OFF"
|
||||
export CMAKE_OSX_ARCHITECTURES="$ARCHITECTURE"
|
||||
else
|
||||
CXXFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
|
||||
CXXFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas -static-libstdc++"
|
||||
CFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
|
||||
PLATFORM_CMAKE_OPTIONS="-DFSO_BUILD_APPIMAGE=ON"
|
||||
fi
|
||||
@@ -30,6 +30,8 @@ fi
|
||||
CMAKE_OPTIONS="$JOB_CMAKE_OPTIONS"
|
||||
if [[ "$COMPILER" =~ ^clang.*$ ]]; then
|
||||
CMAKE_OPTIONS="$CMAKE_OPTIONS -DCLANG_USE_LIBCXX=ON"
|
||||
# force clang to silently allow -static-libstdc++ flag
|
||||
CXXFLAGS="$CXXFLAGS -Qunused-arguments"
|
||||
fi
|
||||
|
||||
mkdir build
|
||||
|
||||
@@ -26,7 +26,7 @@ elif [ "$OS" = "Windows" ]; then
|
||||
echo "debug_name=$(get_package_name)-debug-$ARCH-$SIMD.7z" >> $GITHUB_OUTPUT
|
||||
echo "debug_mime=$(file -b --mime-type "$(pwd)/$(get_package_name)-debug-$ARCH-$SIMD.7z")" >> $GITHUB_OUTPUT
|
||||
elif [ "$OS" = "Mac" ]; then
|
||||
tar -cvzf "$(get_package_name)-builds-Mac.tar.gz" *
|
||||
tar -cvzf "$(get_package_name)-builds-Mac.tar.gz" *.app
|
||||
|
||||
echo "package_path=$(pwd)/$(get_package_name)-builds-Mac.tar.gz" >> $GITHUB_OUTPUT
|
||||
echo "package_name=$(get_package_name)-builds-Mac.tar.gz" >> $GITHUB_OUTPUT
|
||||
|
||||
@@ -15,7 +15,7 @@ if [ "$UPLOAD_TYPE" = "nightly" ]; then
|
||||
any_success=true
|
||||
fi
|
||||
|
||||
if SSHPASS=$DATACORDER_SSHPASS upload_files_to_sftp "$DATACORDER_USER@porphyrion.feralhosting.com" "www/datacorder.porphyrion.feralhosting.com/public_html/builds/nightly"; then
|
||||
if SSHPASS=$DATACORDER_SSHPASS upload_files_to_sftp "$DATACORDER_USER@perses.feralhosting.com" "www/datacorder.perses.feralhosting.com/public_html/builds/nightly"; then
|
||||
any_success=true
|
||||
fi
|
||||
|
||||
@@ -24,7 +24,7 @@ if [ "$UPLOAD_TYPE" = "nightly" ]; then
|
||||
exit 1
|
||||
fi
|
||||
elif [ "$UPLOAD_TYPE" = "test" ]; then
|
||||
SSHPASS=$DATACORDER_SSHPASS upload_files_to_sftp "$DATACORDER_USER@porphyrion.feralhosting.com" "www/datacorder.porphyrion.feralhosting.com/public_html/builds/test"
|
||||
SSHPASS=$DATACORDER_SSHPASS upload_files_to_sftp "$DATACORDER_USER@perses.feralhosting.com" "www/datacorder.perses.feralhosting.com/public_html/builds/test"
|
||||
else
|
||||
echo "Unknown upload type $UPLOAD_TYPE"
|
||||
exit 1
|
||||
|
||||
+7
-3
@@ -19,7 +19,7 @@
|
||||
# HLP_API:
|
||||
# HLP_KEY:
|
||||
|
||||
# LINUX_RESULT: bool, if the linux builds were sucessfully uploaded
|
||||
# LINUX_RESULT: bool, if the linux builds were successfully uploaded
|
||||
# WINDOWS_RESULT: bool, if the windows builds were successfully uploaded
|
||||
|
||||
import sys
|
||||
@@ -137,8 +137,8 @@ def main():
|
||||
"pass": os.environ["INDIEGAMES_SSHPASS"],
|
||||
"path": "public_html/builds/{type}/{version}/",
|
||||
"mirrors": (
|
||||
"https://porphyrion.feralhosting.com/datacorder/builds/{type}/{version}/{file}",
|
||||
"http://scp.indiegames.us/builds/{type}/{version}/{file}",
|
||||
"https://perses.feralhosting.com/datacorder/builds/{type}/{version}/{file}",
|
||||
"https://scp.indiegames.us/builds/{type}/{version}/{file}",
|
||||
),
|
||||
},
|
||||
"nebula": {
|
||||
@@ -260,6 +260,10 @@ def main():
|
||||
if "Linux" not in groups.keys():
|
||||
print("ERROR: No Linux builds were detected!")
|
||||
sys.exit(1)
|
||||
|
||||
if "Mac" not in groups.keys():
|
||||
print("ERROR: No Mac builds were detected!")
|
||||
sys.exit(1)
|
||||
|
||||
# z64: What dose this do???
|
||||
# print(installer.render_installer_config(version, groups, config))
|
||||
|
||||
+13
-6
@@ -18,11 +18,11 @@ Launchers, if you don't have one already:
|
||||
Cross-platform: [url=https://www.hard-light.net/forums/index.php?topic=89162]wxLauncher 0.12.x Test Build[/url] (ongoing project for a unified launcher, you should upgrade to the latest RC/test build if you have not yet)
|
||||
[b]Important:[/b] For best compatibility with FSO 3.8 and later you should use at least wxLauncher 0.12.
|
||||
|
||||
Windows: [url=http://scp.fsmods.net/builds/Launcher55g.zip]Launcher 5.5g[/url] ([url=http://scp.indiegames.us/builds/Launcher55g.zip]Mirror[/url]) ([url=https://www.mediafire.com/?wdvzn7hhhzh418m]Mirror[/url]) Not compatible with Windows 8+, use wxLauncher above
|
||||
Windows: [url=http://scp.fsmods.net/builds/Launcher55g.zip]Launcher 5.5g[/url] ([url=https://scp.indiegames.us/builds/Launcher55g.zip]Mirror[/url]) ([url=https://www.mediafire.com/?wdvzn7hhhzh418m]Mirror[/url]) Not compatible with Windows 8+, use wxLauncher above
|
||||
OS X: Soulstorm's [url=https://www.hard-light.net/forums/index.php/topic,51391.0.html]OS X Launcher 3.0[/url]
|
||||
Linux: [url=https://www.hard-light.net/forums/index.php/topic,53206.0.html]YAL[/url] or [url=https://www.hard-light.net/wiki/index.php/Fs2_open_on_Linux/Graphics_Settings]by hand[/url] or whatever you can figure out.[/hidden]
|
||||
|
||||
[img]http://scp.indiegames.us/img/windows-icon.png[/img] [color=green][size=12pt]Windows (32/64-bit)[/size][/color]
|
||||
[img]https://scp.indiegames.us/img/windows-icon.png[/img] [color=green][size=12pt]Windows (32/64-bit)[/size][/color]
|
||||
[size=8pt]Compiled using GitHub Actions on Windows Server 2019 (10.0.17763), Visual Studio Enterprise 2019[/size]
|
||||
|
||||
[b]64-bit:[/b] ${build(groups["Win64"].mainFile)}
|
||||
@@ -44,7 +44,7 @@ Linux: [url=https://www.hard-light.net/forums/index.php/topic,53206.0.html]YAL[
|
||||
Don't want to deal with that? Use [url=https://www.hard-light.net/forums/index.php?topic=94068.0]Knossos[/url] and it will download the best build specifically for your PC!
|
||||
[/hidden]
|
||||
|
||||
[img]http://scp.indiegames.us/img/linux-icon.png[/img] [color=green][size=12pt]Linux 64-bit[/size][/color]
|
||||
[img]https://scp.indiegames.us/img/linux-icon.png[/img] [color=green][size=12pt]Linux 64-bit[/size][/color]
|
||||
[size=8pt]Compiled with Ubuntu 16.04 LTS 64-bit, GCC 5[/size]
|
||||
${build(groups["Linux"].mainFile)}
|
||||
|
||||
@@ -52,14 +52,21 @@ These builds use a mechanism called [url=https://appimage.org/]AppImage[/url] wh
|
||||
Alternatively, if there is a package in your software repository then you should use that. If you are the maintainer of such a package for a distribution then let us know and we will include that here.
|
||||
|
||||
|
||||
[img]http://scp.indiegames.us/img/mac-icon.png[/img] [color=green][size=12pt]OS X[/size][/color]
|
||||
[b][color=red]Not available[/color][/b] We recently lost access to our Mac CI environment which we usually used for compiling these builds so for the time being, there will be no builds for this OS.
|
||||
[img]https://scp.indiegames.us/img/mac-icon.png[/img] [color=green][size=12pt]macOS[/size][/color]
|
||||
[size=8pt]macOS 10.9+, 64-bit (Intel)[/size]
|
||||
${build(groups["Mac"].mainFile)}
|
||||
|
||||
These builds are not signed and so by default will fail to launch. To run them simply right-click on the app, click open, then click open again on the security confirmation dialog. You should only have to do this once for each app.
|
||||
If running the game through Knossos or Knossos.NET this step should not be necessary.
|
||||
|
||||
[size=8pt][color=red][b]NOTE:[/b][/color] macOS builds currently have limited support and may exhibit issues not present on other platforms.[/size]
|
||||
|
||||
|
||||
[hidden=TrackIR Users]
|
||||
[size=12pt]Important!![/size]
|
||||
An external DLL is required for FSO to use TrackIR functions. The following DLL is simply unpacked in to your main FreeSpace2 root dir.
|
||||
TrackIR is only supported on Windows.
|
||||
[url=https://www.mediafire.com/download.php?4zw024zrh44etse]TrackIR SCP DLL[/url] ([url=http://scp.fsmods.net/builds/scptrackir.zip]Mirror[/url]) ([url=http://scp.indiegames.us/builds/scptrackir.zip]Mirror[/url])[/hidden]
|
||||
[url=https://www.mediafire.com/download.php?4zw024zrh44etse]TrackIR SCP DLL[/url] ([url=http://scp.fsmods.net/builds/scptrackir.zip]Mirror[/url]) ([url=https://scp.indiegames.us/builds/scptrackir.zip]Mirror[/url])[/hidden]
|
||||
|
||||
Known issues:
|
||||
[list]
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
set -ex
|
||||
|
||||
if [ "$NIGHTLY_BUILD" = true ]; then
|
||||
echo "Generating bintray config..."
|
||||
sed -e "s/\$VERSION_NAME/$VERSION_NAME/" ci/bintray.template.json > ci/bintray.json
|
||||
fi
|
||||
@@ -1,20 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
set -ex
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
sudo add-apt-repository -y "ppa:msulikowski/valgrind" # For fixing a bug with valgrind 3.11 which does not recognize the rdrand instruction
|
||||
|
||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key|sudo apt-key add -
|
||||
sudo add-apt-repository -y 'deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main'
|
||||
|
||||
sudo apt-get -yq update
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
# Nothing to do here
|
||||
:
|
||||
elif [ "$TRAVIS_OS_NAME" = "windows" ]; then
|
||||
# Nothing to do here
|
||||
:
|
||||
fi
|
||||
@@ -1,50 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -ex
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
mkdir -p /tmp/builds
|
||||
if [ "$RELEASE_BUILD" = true ]; then
|
||||
# Package the source code in release builds
|
||||
PARENT_DIR="$(basename "$PWD")"
|
||||
(cd .. && tar -czvf /tmp/builds/$PACKAGE_NAME-source-Unix.tar.gz --exclude-vcs "$PARENT_DIR")
|
||||
fi
|
||||
fi
|
||||
|
||||
mkdir -p build
|
||||
cd build
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
CXXFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
|
||||
CFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
|
||||
|
||||
export CXXFLAGS
|
||||
export CFLAGS
|
||||
CMAKE="cmake -G Ninja -DFSO_FATAL_WARNINGS=ON $CMAKE_OPTIONS"
|
||||
if [ "$BUILD_DEPLOYMENT" = true ]; then
|
||||
for config in $BUILD_CONFIGS
|
||||
do
|
||||
mkdir -p $config
|
||||
cd $config
|
||||
eval $CMAKE -DFSO_INSTALL_DEBUG_FILES=ON -DCMAKE_BUILD_TYPE=$config -DCMAKE_INSTALL_PREFIX="/tmp/release/$config" \
|
||||
-DFSO_BUILD_APPIMAGE=ON -DFSO_BUILD_INCLUDED_LIBS=ON -DFFMPEG_USE_PRECOMPILED=ON -DFSO_BUILD_QTFRED=OFF ../..
|
||||
cd ..
|
||||
done
|
||||
else
|
||||
eval $CMAKE -DCMAKE_BUILD_TYPE=$CONFIGURATION -DFSO_BUILD_TESTS=ON -DFSO_BUILD_INCLUDED_LIBS=ON -DFSO_BUILD_QTFRED=OFF ..
|
||||
fi
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
if [ "$BUILD_DEPLOYMENT" = true ]; then
|
||||
cmake -G "Xcode" -DFSO_FATAL_WARNINGS=ON -DFSO_INSTALL_DEBUG_FILES=ON -DCMAKE_INSTALL_PREFIX="/tmp/release" ..
|
||||
else
|
||||
cmake -G "Xcode" $CMAKE_OPTIONS ..
|
||||
fi
|
||||
elif [ "$TRAVIS_OS_NAME" = "windows" ]; then
|
||||
if [ "$CMAKE_GENERATOR" = "Ninja" ]; then
|
||||
cmake -DFSO_USE_SPEECH="OFF" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
|
||||
-DFSO_BUILD_FRED2="OFF" -G "$CMAKE_GENERATOR" ..
|
||||
else
|
||||
cmake -DFSO_USE_SPEECH="ON" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
|
||||
-DMSVC_SIMD_INSTRUCTIONS=SSE2 -DFSO_BUILD_FRED2="ON" -G "$CMAKE_GENERATOR" -T "$CMAKE_TOOLSET" ..
|
||||
fi
|
||||
fi
|
||||
@@ -1,74 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
RELEASE_BUILD=false
|
||||
NIGHTLY_BUILD=false
|
||||
TEST_BUILD=false
|
||||
|
||||
BUILD_DEPLOYMENT=false
|
||||
BUILD_CONFIGS="Release FastDebug"
|
||||
VERSION_NAME=""
|
||||
PACKAGE_NAME=""
|
||||
|
||||
RELEASE_PATTERN="^release_(.*)$"
|
||||
NIGHTLY_PATTERN="^nightly_(.*)$"
|
||||
TEST_BUILD_PATTERN="^test\/(.*)$"
|
||||
|
||||
# These are for testing
|
||||
NIGHTLY_TEST=false
|
||||
RELEASE_TEST=false
|
||||
TEST_BUILD_TEST=false
|
||||
|
||||
if [ "$RELEASE_TEST" = true ] || [[ "$TRAVIS_TAG" =~ $RELEASE_PATTERN ]]; then
|
||||
echo "This is a release tag!";
|
||||
RELEASE_BUILD=true;
|
||||
PACKAGE_NAME="fs2_open_${BASH_REMATCH[1]}";
|
||||
fi
|
||||
if [ "$NIGHTLY_TEST" = true ] || [[ "$TRAVIS_TAG" =~ $NIGHTLY_PATTERN ]]; then
|
||||
echo "This is a nightly tag!";
|
||||
NIGHTLY_BUILD=true;
|
||||
VERSION_NAME="${BASH_REMATCH[1]}";
|
||||
PACKAGE_NAME="nightly_${BASH_REMATCH[1]}";
|
||||
fi
|
||||
if [ "$TEST_BUILD_TEST" = true ] || [[ "$TRAVIS_PULL_REQUEST" == "false" && "$TRAVIS_BRANCH" =~ $TEST_BUILD_PATTERN ]]; then
|
||||
echo "This is a test build branch!";
|
||||
TEST_BUILD=true;
|
||||
if [ "$TEST_BUILD_TEST" = true ]; then
|
||||
VERSION_NAME="test";
|
||||
PACKAGE_NAME="test_test";
|
||||
else
|
||||
VERSION_NAME="${BASH_REMATCH[1]}";
|
||||
PACKAGE_NAME="test_${BASH_REMATCH[1]}";
|
||||
fi
|
||||
|
||||
# Override the revision string so that the builds are named correctly
|
||||
echo "set(FSO_VERSION_REVISION_STR $VERSION_NAME)" > "$TRAVIS_BUILD_DIR/version_override.cmake"
|
||||
fi
|
||||
|
||||
if ([ "$RELEASE_BUILD" = true ] || [ "$NIGHTLY_BUILD" = true ] || [ "$TEST_BUILD" = true ]); then
|
||||
BUILD_DEPLOYMENT=true;
|
||||
fi
|
||||
|
||||
if [ "$BUILD_DEPLOYMENT" = true ]; then
|
||||
if ([ "$TRAVIS_OS_NAME" = "linux" ] && (! [[ "$CC" =~ ^gcc-5.*$ ]])); then
|
||||
echo "Skipping non-release compiler";
|
||||
exit 0;
|
||||
fi
|
||||
|
||||
if ([[ "$CONFIGURATION" == "Debug" ]]); then
|
||||
echo "Skipping non-release configuration";
|
||||
exit 0;
|
||||
fi
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "windows" ]; then
|
||||
echo "Skipping non-release platform"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
export RELEASE_BUILD
|
||||
export NIGHTLY_BUILD
|
||||
export TEST_BUILD
|
||||
export BUILD_DEPLOYMENT
|
||||
export BUILD_CONFIGS
|
||||
export VERSION_NAME
|
||||
export PACKAGE_NAME
|
||||
@@ -1,89 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
set -u
|
||||
|
||||
if [[ ! "$(curl -V)" == *"sftp"* ]]; then
|
||||
# Before
|
||||
echo "Before:"
|
||||
curl -V
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
|
||||
if [ -f ~/curl_cache/curl*.deb ]; then
|
||||
cd ~/curl_cache
|
||||
sudo dpkg -i libcurl3*.deb
|
||||
sudo dpkg -i curl*.deb
|
||||
else
|
||||
# Since the Travis CI people are not capable of enabling SSH/SCP support for their libcurl we need to build that manually...
|
||||
# These commands are based on the tutorial from here: http://zeroset.mnim.org/2013/03/14/sftp-support-for-curl-in-ubuntu-12-10-quantal-quetzal-and-later/
|
||||
mkdir /tmp/curl
|
||||
cd /tmp/curl
|
||||
sudo apt-get update
|
||||
sudo apt-get install build-essential debhelper libssh2-1-dev libgnutls-dev libidn11-dev libkrb5-dev libldap2-dev libnss3-dev librtmp-dev libtool openssh-server quilt
|
||||
apt-get source curl
|
||||
sudo apt-get build-dep curl
|
||||
|
||||
cd curl-*
|
||||
export DEB_BUILD_OPTIONS="nocheck"
|
||||
sudo dpkg-buildpackage -uc -us -j"$(grep -c ^processor /proc/cpuinfo)"
|
||||
|
||||
cd ..
|
||||
dpkg -l | grep curl
|
||||
ls -al
|
||||
|
||||
if [ ! -d ~/curl_cache ]; then
|
||||
mkdir ~/curl_cache
|
||||
fi
|
||||
|
||||
cp libcurl3*.deb curl*.deb ~/curl_cache
|
||||
|
||||
sudo dpkg -i libcurl3*.deb
|
||||
sudo dpkg -i curl*.deb
|
||||
fi
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
brew install libssh2
|
||||
|
||||
if [ -d ~/curl_cache/curl ]; then
|
||||
cd ~/curl_cache/curl
|
||||
sudo make install
|
||||
else
|
||||
mkdir /tmp/curl
|
||||
cd /tmp/curl
|
||||
|
||||
curl -LO "https://curl.haxx.se/download/curl-7.64.0.tar.bz2"
|
||||
tar -xjf curl-7.64.0.tar.bz2
|
||||
|
||||
cd curl-7.64.0
|
||||
./configure --disable-debug --disable-dependency-tracking --disable-silent-rules --with-libssh2 --with-darwinssl --without-ca-bundle --without-ca-path
|
||||
make -j"$(sysctl hw.logicalcpu | cut -d " " -f 2)"
|
||||
|
||||
if [ ! -d ~/curl_cache ]; then
|
||||
mkdir ~/curl_cache
|
||||
fi
|
||||
|
||||
cp -a . ~/curl_cache/curl
|
||||
sudo make install
|
||||
fi
|
||||
export PATH=/usr/local/bin:$PATH
|
||||
fi
|
||||
|
||||
# After
|
||||
echo "After:"
|
||||
curl -V
|
||||
fi
|
||||
|
||||
cd /tmp/builds
|
||||
|
||||
for file in *; do
|
||||
if [ "$TEST_BUILD" = true ]; then
|
||||
# Upload to datacorder
|
||||
curl -k "sftp://porphyrion.feralhosting.com/www/datacorder.porphyrion.feralhosting.com/public_html/builds/test/$VERSION_NAME/" --user "$DATACORDER_USER:$DATACORDER_PASSWORD" -T "$file" --ftp-create-dirs
|
||||
else
|
||||
# Upload to indiegames
|
||||
curl -k "sftp://scp.indiegames.us/~/public_html/builds/nightly/$VERSION_NAME/" --user "$INDIEGAMES_USER:$INDIEGAMES_PASSWORD" -T "$file" --ftp-create-dirs
|
||||
|
||||
# Upload to datacorder
|
||||
curl -k "sftp://porphyrion.feralhosting.com/~/www/datacorder.porphyrion.feralhosting.com/public_html/builds/nightly/$VERSION_NAME/" --user "$DATACORDER_USER:$DATACORDER_PASSWORD" -T "$file" --ftp-create-dirs
|
||||
fi
|
||||
done
|
||||
@@ -1,47 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -ex
|
||||
|
||||
FILENAME=
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
if [ ! -d "$HOME/cmake-3.8/bin" ]; then
|
||||
# If the cache does not currently contain CMake then download and install it
|
||||
mkdir -p $HOME/cmake-3.8/
|
||||
|
||||
wget -O /tmp/cmake.tar.gz --no-check-certificate https://cmake.org/files/v3.8/cmake-3.8.2-Linux-x86_64.tar.gz
|
||||
tar -xzf /tmp/cmake.tar.gz -C $HOME/cmake-3.8/ --strip-components=1
|
||||
fi
|
||||
export PATH=$HOME/cmake-3.8/bin:$PATH
|
||||
|
||||
cd $HOME
|
||||
|
||||
if [ "${BUILD_DEPLOYMENT}" = true ]; then
|
||||
wget -O appimagetool -c "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage" # (64-bit)
|
||||
chmod a+x ./appimagetool
|
||||
|
||||
wget -O linuxdeployqt -c "https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage" # (64-bit)
|
||||
chmod a+x ./linuxdeployqt
|
||||
fi
|
||||
|
||||
sudo apt-get -yq install valgrind
|
||||
|
||||
if [[ "$CC" = "clang-9" ]]; then
|
||||
sudo apt-get -yq install clang-9 clang-tidy-9
|
||||
fi
|
||||
|
||||
if [[ "$CC" = "clang-4.0" ]]; then
|
||||
# Fix a header bug present in ubuntu...
|
||||
sudo ln -s /usr/include/libcxxabi/__cxxabi_config.h /usr/include/c++/v1/__cxxabi_config.h
|
||||
fi
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
gem install xcpretty
|
||||
|
||||
brew update
|
||||
brew outdated cmake || brew upgrade cmake
|
||||
elif [ "$TRAVIS_OS_NAME" = "windows" ]; then
|
||||
choco install mingw ninja
|
||||
fi
|
||||
|
||||
cmake --version
|
||||
@@ -1,68 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
set -ex
|
||||
mkdir -p /tmp/builds
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
cd build
|
||||
for config in $BUILD_CONFIGS
|
||||
do
|
||||
cd "$config"
|
||||
|
||||
# Compile all targets
|
||||
ninja all
|
||||
|
||||
# Install Freespace2 targets
|
||||
cmake -DCMAKE_INSTALL_PREFIX=/tmp/release/$config/fso -DCOMPONENT=Unspecified -P cmake_install.cmake
|
||||
cmake -DCMAKE_INSTALL_PREFIX=/tmp/release/$config/fso -DCOMPONENT=Freespace2 -P cmake_install.cmake
|
||||
|
||||
# We need to be a bit creative for determining the AppImage name since we don't want to hard-code the name
|
||||
FILENAME="$(find /tmp/release/$config/fso/bin -name 'fs2_open_*' -type f -printf "%f\n").AppImage"
|
||||
$HOME/appimagetool -n /tmp/release/$config/fso "/tmp/release/$config/fso/$FILENAME"
|
||||
|
||||
: <<'END'
|
||||
# Install qtFRED targets
|
||||
cmake -DCMAKE_INSTALL_PREFIX=/tmp/release/$config/qtfred/usr -DCOMPONENT=Unspecified -P cmake_install.cmake
|
||||
cmake -DCMAKE_INSTALL_PREFIX=/tmp/release/$config/qtfred/usr -DCOMPONENT=qtFRED -P cmake_install.cmake
|
||||
|
||||
PREV="$(pwd)"
|
||||
cd /tmp/release/$config/qtfred
|
||||
|
||||
unset QTDIR; unset QT_PLUGIN_PATH; unset LD_LIBRARY_PATH
|
||||
$HOME/linuxdeployqt usr/qtfred.desktop -bundle-non-qt-libs
|
||||
# Move our AppRun script to the right location
|
||||
mv usr/AppRun AppRun
|
||||
|
||||
echo "Embed newer libstdc++ for distros that don't come with it (ubuntu 14.04)";
|
||||
mkdir -p usr/optional/; mkdir -p usr/optional/libstdc++/;
|
||||
cp /usr/lib/x86_64-linux-gnu/libstdc++.so.6 ./usr/optional/libstdc++/;
|
||||
|
||||
$HOME/appimagetool -n . "$(find /tmp/release/$config/qtfred/usr/bin -name 'qtfred_*' -type f -printf "%f\n").AppImage"
|
||||
|
||||
cd "$PREV"
|
||||
END
|
||||
|
||||
cd ..
|
||||
done
|
||||
|
||||
cp `find /tmp/release -name '*.AppImage' -print` /tmp/release
|
||||
(cd /tmp/release && tar -cvzf /tmp/builds/$PACKAGE_NAME-builds-Linux.tar.gz *.AppImage)
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
cd build
|
||||
|
||||
for config in $BUILD_CONFIGS
|
||||
do
|
||||
cmake --build . --config "$config" --target install | tee build.log \
|
||||
| xcpretty
|
||||
XCODE_RET=${PIPESTATUS[0]}
|
||||
if [ "$XCODE_RET" -ne "0" ]; then
|
||||
tar -cvzf build.log.tar.gz build.log
|
||||
curl --upload-file build.log.tar.gz "https://transfer.sh/build.log.tar.gz"
|
||||
exit $XCODE_RET
|
||||
fi
|
||||
done
|
||||
|
||||
ls -al /tmp/release
|
||||
|
||||
(cd /tmp/release && tar -cvzf /tmp/builds/$PACKAGE_NAME-builds-MacOSX.tar.gz *)
|
||||
fi
|
||||
@@ -1,30 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
set -e
|
||||
|
||||
cd build
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
ninja -k 20 all
|
||||
|
||||
if [ "$CONFIGURATION" = "Debug" ]; then
|
||||
valgrind --leak-check=full --error-exitcode=1 --gen-suppressions=all \
|
||||
--suppressions="$TRAVIS_BUILD_DIR/ci/travis/valgrind.supp" ./bin/unittests --gtest_shuffle
|
||||
else
|
||||
./bin/unittests --gtest_shuffle
|
||||
fi
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
cmake --build . --config "$CONFIGURATION" | tee build.log | xcpretty
|
||||
XCODE_RET=${PIPESTATUS[0]}
|
||||
if [ "$XCODE_RET" -ne "0" ]; then
|
||||
tar -cvzf build.log.tar.gz build.log
|
||||
curl --upload-file build.log.tar.gz "https://keep.sh"
|
||||
exit $XCODE_RET
|
||||
fi
|
||||
elif [ "$TRAVIS_OS_NAME" = "windows" ]; then
|
||||
if [ "$CMAKE_GENERATOR" = "Ninja" ]; then
|
||||
cmake --build . --config "$CONFIGURATION"
|
||||
else
|
||||
cmake --build . --config "$CONFIGURATION" -- /verbosity:minimal
|
||||
fi
|
||||
fi
|
||||
+30
-17
@@ -67,30 +67,43 @@ ENDIF(EXISTS \"${CMAKE_CURRENT_BINARY_DIR}/${TARGET}/${FILE}\")
|
||||
ENDFUNCTION(EP_CHECK_FILE_EXISTS)
|
||||
|
||||
MACRO(COPY_FILE_TO_TARGET _target _file)
|
||||
if(UNIX)
|
||||
ADD_CUSTOM_COMMAND(
|
||||
TARGET ${_target} POST_BUILD
|
||||
COMMAND cp -a "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/"
|
||||
COMMENT "copying '${_file}'..."
|
||||
)
|
||||
if (IS_DIRECTORY "${_file}")
|
||||
get_filename_component(_dirName "${_file}" NAME)
|
||||
if (PLATFORM_MAC AND ("${_file}" MATCHES ".framework$"))
|
||||
# This is stupid, but it preserves symlinks, unlike copy_directory_if_different.
|
||||
# Otherwise we end up creating duplicate files in the copied framework.
|
||||
ADD_CUSTOM_COMMAND(
|
||||
TARGET ${_target} POST_BUILD
|
||||
COMMAND rsync -rlq "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}"
|
||||
COMMENT "copying '${_file}'..."
|
||||
VERBATIM
|
||||
)
|
||||
else()
|
||||
ADD_CUSTOM_COMMAND(
|
||||
TARGET ${_target} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/${_dirName}"
|
||||
COMMENT "copying '${_file}'..."
|
||||
VERBATIM
|
||||
)
|
||||
endif()
|
||||
else()
|
||||
ADD_CUSTOM_COMMAND(
|
||||
TARGET ${_target} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/"
|
||||
COMMENT "copying '${_file}'..."
|
||||
TARGET ${_target} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/"
|
||||
COMMENT "copying '${_file}'..."
|
||||
VERBATIM
|
||||
)
|
||||
endif()
|
||||
endmacro(COPY_FILE_TO_TARGET)
|
||||
|
||||
MACRO(COPY_FILES_TO_TARGET _target)
|
||||
if(UNIX)
|
||||
ADD_CUSTOM_COMMAND(
|
||||
TARGET ${_target} POST_BUILD
|
||||
COMMAND mkdir -p "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/"
|
||||
COMMENT "Creating '$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/'..."
|
||||
)
|
||||
endif()
|
||||
|
||||
ADD_CUSTOM_COMMAND(
|
||||
TARGET ${_target} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/"
|
||||
COMMENT "Creating '$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/'..."
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
FOREACH(file IN LISTS TARGET_COPY_FILES)
|
||||
COPY_FILE_TO_TARGET("${_target}" "${file}")
|
||||
ENDFOREACH(file)
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ if (EXISTS "${PROJECT_SOURCE_DIR}/version_override.cmake")
|
||||
endif()
|
||||
|
||||
set_if_not_defined(FSO_VERSION_MAJOR 23)
|
||||
set_if_not_defined(FSO_VERSION_MINOR 1)
|
||||
set_if_not_defined(FSO_VERSION_MINOR 3)
|
||||
set_if_not_defined(FSO_VERSION_BUILD 0)
|
||||
|
||||
# A numeric revision e.g. the CI build number
|
||||
|
||||
+9
-18
@@ -56,12 +56,6 @@ extern const int Num_ai_flag_names;
|
||||
#define AIDO_DOCK_NOW 2 // Immediately move into dock position. For ships that start mission docked.
|
||||
#define AIDO_UNDOCK 3 // Set goal of undocking with object.
|
||||
|
||||
// Submodes for seeking safety.
|
||||
#define AISS_1 41 // Pick a spot to fly to.
|
||||
#define AISS_2 42 // Flying to spot.
|
||||
#define AISS_3 43 // Gotten near spot, fly about there.
|
||||
#define AISS_1a 44 // Pick a new nearby spot because we are endangered, then go to AISS_2
|
||||
|
||||
// Flags to ai_turn_towards_vector().
|
||||
#define AITTV_FAST (1<<0) // Turn fast, not slowed down based on skill level.
|
||||
#define AITTV_VIA_SEXP (1<<1) // Goober5000 - via sexp
|
||||
@@ -93,7 +87,7 @@ extern const int Num_ai_flag_names;
|
||||
#define AIM_BAY_DEPART 18 // Departing to a fighter bay, following path to do so
|
||||
#define AIM_SENTRYGUN 19 // AI mode for sentry guns only (floating turrets)
|
||||
#define AIM_WARP_OUT 20 // Commence warp out sequence. Point in legal direction. Then call John's code.
|
||||
#define AIM_FLY_TO_SHIP 21 // [Kazan] Fly to a ship, doesn't matter if it's hostile or friendly -- for Autopilot usage
|
||||
#define AIM_FLY_TO_SHIP 21 // Rendezvous with a ship. Like stay-near, but non-perpetual.
|
||||
#define AIM_LUA 22 // Generic Lua-based AI mode
|
||||
|
||||
#define MAX_AI_BEHAVIORS 23 // Number of AIM_xxxx types
|
||||
@@ -186,6 +180,12 @@ typedef struct ai_class {
|
||||
#define AIS_UNDOCK_3 33
|
||||
#define AIS_UNDOCK_4 34
|
||||
|
||||
// Submodes for seeking safety.
|
||||
#define AISS_1 41 // Pick a spot to fly to.
|
||||
#define AISS_2 42 // Flying to spot.
|
||||
#define AISS_3 43 // Gotten near spot, fly about there.
|
||||
#define AISS_1a 44 // Pick a new nearby spot because we are endangered, then go to AISS_2. (Not implemented.)
|
||||
|
||||
// Submodes for Guard behavior
|
||||
#define AIS_GUARD_PATROL 101
|
||||
#define AIS_GUARD_ATTACK 102
|
||||
@@ -240,7 +240,6 @@ typedef struct ai_info {
|
||||
flagset<AI::AI_Flags> ai_flags; // Special flags for AI behavior.
|
||||
int shipnum; // Ship using this slot, -1 means none.
|
||||
|
||||
int behavior; // AI behavior; vestigial field from early development of FS1
|
||||
int mode;
|
||||
int previous_mode;
|
||||
int mode_time; // timestamp at which current mode elapses.
|
||||
@@ -308,6 +307,7 @@ typedef struct ai_info {
|
||||
fix submode_start_time; // time at which we entered the current submode
|
||||
int submode_parm0; // parameter specific to current submode
|
||||
int submode_parm1; // SUSHI: Another optional parameter
|
||||
float submode_float0; // Goober5000: a float parameter
|
||||
fix next_predict_pos_time; // Next time to predict position.
|
||||
|
||||
int next_dynamic_path_check_time; //ETP: Time of next path check in ai_new_maybe_reposition_attack_subsys
|
||||
@@ -373,11 +373,6 @@ typedef struct ai_info {
|
||||
float ai_turret_max_aim_update_delay;
|
||||
flagset<AI::Profile_Flags> ai_profile_flags; //Holds AI_Profiles flags (possibly overriden by AI class) that actually apply to AI
|
||||
|
||||
|
||||
union {
|
||||
float stay_near_distance; // Distance to stay within for AIM_STAY_NEAR mode.
|
||||
};
|
||||
|
||||
ship_subsys* targeted_subsys; // Targeted subobject on current target. NULL if none;
|
||||
ship_subsys* last_subsys_target; // last known subsystem target
|
||||
int targeted_subsys_parent; // Parent objnum of subobject, not necessarily targeted
|
||||
@@ -565,7 +560,7 @@ extern void ai_attack_wing(object *attacker, int wingnum);
|
||||
extern void ai_deathroll_start(object *ship_obj);
|
||||
extern int set_target_objnum(ai_info *aip, int objnum);
|
||||
extern void ai_form_on_wing(object *objp, object *goal_objp);
|
||||
extern void ai_do_stay_near(object *objp, object *other_obj, float dist);
|
||||
extern void ai_do_stay_near(object *objp, object *other_obj, float dist, int additional_data);
|
||||
extern ship_subsys *set_targeted_subsys(ai_info *aip, ship_subsys *new_subsys, int parent_objnum);
|
||||
extern void ai_rearm_repair( object *objp, int docker_index, object *goal_objp, int dockee_index );
|
||||
extern void ai_add_rearm_goal( object *requester_objp, object *support_objp );
|
||||
@@ -625,10 +620,6 @@ int get_nearest_objnum(int objnum, int enemy_team_mask, int enemy_wing, float ra
|
||||
// moved to header file by Goober5000
|
||||
void ai_announce_ship_dying(object *dying_objp);
|
||||
|
||||
// added by kazan
|
||||
void ai_start_fly_to_ship(object *objp, int shipnum);
|
||||
void ai_fly_to_ship();
|
||||
|
||||
//Moved declaration here for player ship -WMC
|
||||
void ai_process_subobjects(int objnum);
|
||||
|
||||
|
||||
+2
-1
@@ -122,7 +122,7 @@ namespace AI {
|
||||
Smart_shield_management,
|
||||
Smart_subsystem_targeting_for_turrets,
|
||||
Strict_turret_tagged_only_targeting,
|
||||
Support_dont_add_primaries, //Prevents support ship from equipping new primary as requested in http://scp.indiegames.us/mantis/view.php?id=3198
|
||||
Support_dont_add_primaries, //Prevents support ship from equipping new primary as requested in https://scp.indiegames.us/mantis/view.php?id=3198
|
||||
Turrets_ignore_target_radius,
|
||||
Use_actual_primary_range,
|
||||
Use_subsystem_path_point_radii,
|
||||
@@ -156,6 +156,7 @@ namespace AI {
|
||||
Whackable_debris,
|
||||
Whackable_asteroids,
|
||||
Dynamic_goals_afterburn_hard,
|
||||
Hudsquadmsg_tactical_disarm_disable,
|
||||
|
||||
NUM_VALUES
|
||||
};
|
||||
|
||||
@@ -552,7 +552,9 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
profile->flags.set(AI::Profile_Flags::All_nonshielded_ships_can_manage_ets, temp);
|
||||
}
|
||||
|
||||
set_flag(profile, "$no directional bias for missile and ship turning:", AI::Profile_Flags::No_turning_directional_bias);
|
||||
// ----------
|
||||
|
||||
set_flag(profile, "$no directional bias for missile and ship turning:", AI::Profile_Flags::No_turning_directional_bias);
|
||||
|
||||
set_flag(profile, "$respect ship axial turnrate differences:", AI::Profile_Flags::Use_axial_turnrate_differences);
|
||||
|
||||
@@ -623,6 +625,8 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
|
||||
set_flag(profile, "$dynamic goals afterburn hard:", AI::Profile_Flags::Dynamic_goals_afterburn_hard);
|
||||
|
||||
set_flag(profile, "$hud squad messages use tactical disarm/disable:", AI::Profile_Flags::Hudsquadmsg_tactical_disarm_disable);
|
||||
|
||||
// if we've been through once already and are at the same place, force a move
|
||||
if (saved_Mp && (saved_Mp == Mp))
|
||||
{
|
||||
@@ -812,4 +816,7 @@ void ai_profile_t::reset()
|
||||
if (mod_supports_version(23, 2, 0)) {
|
||||
flags.set(AI::Profile_Flags::Ships_playing_dead_dont_manage_ets);
|
||||
}
|
||||
if (mod_supports_version(23, 4, 0)) {
|
||||
flags.set(AI::Profile_Flags::Hudsquadmsg_tactical_disarm_disable);
|
||||
}
|
||||
}
|
||||
+5
-5
@@ -535,11 +535,11 @@ bool ai_new_maybe_reposition_attack_subsys() {
|
||||
|
||||
// get world pos of eye (stored in geye)
|
||||
ep = &(pm->view_positions[Ships[Pl_objp->instance].current_viewpoint]);
|
||||
model_local_to_global_point(&geye, &ep->pnt, pm->id, 0, &Pl_objp->orient, &Pl_objp->pos);
|
||||
model_local_to_global_point(&geye, &ep->pnt, pm, 0, &Pl_objp->orient, &Pl_objp->pos);
|
||||
|
||||
// get world pos of subsystem
|
||||
vm_vec_unrotate(&gsubpos, &aip->targeted_subsys->system_info->pnt, &En_objp->orient);
|
||||
vm_vec_add2(&gsubpos, &En_objp->pos);
|
||||
polymodel* tgt_pm = model_get(Ship_info[Ships[target_objp->instance].ship_info_index].model_num);
|
||||
model_local_to_global_point(&gsubpos, &vmd_zero_vector, tgt_pm, aip->targeted_subsys->system_info->subobj_num, &En_objp->orient, &En_objp->pos);
|
||||
|
||||
// you're in sight! shoot it!
|
||||
if (ship_subsystem_in_sight(En_objp, aip->targeted_subsys, &geye, &gsubpos, 0))
|
||||
@@ -914,13 +914,13 @@ static void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy)
|
||||
}
|
||||
|
||||
if (tswp->num_secondary_banks > 0) {
|
||||
if (!(En_objp->flags[Object::Object_Flags::Protected]) || (aip->goals[0].ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP))) {
|
||||
if (!(En_objp->flags[Object::Object_Flags::Protected]) || (aip->goals[0].ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISABLE_SHIP_TACTICAL | AI_GOAL_DISARM_SHIP | AI_GOAL_DISARM_SHIP_TACTICAL))) {
|
||||
bool valid_secondary = ai_choose_secondary_weapon(Pl_objp, aip, En_objp);
|
||||
int current_bank = tswp->current_secondary_bank;
|
||||
if (current_bank > -1 && valid_secondary) {
|
||||
weapon_info *swip = &Weapon_info[tswp->secondary_bank_weapons[current_bank]];
|
||||
|
||||
if(!(En_objp->flags[Object::Object_Flags::Protected]) || ((aip->goals[0].ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP)) && swip->wi_flags[Weapon::Info_Flags::Puncture] )) { //override lockdown on protected ships when using anti subsystem weapons - Valathil
|
||||
if(!(En_objp->flags[Object::Object_Flags::Protected]) || ((aip->goals[0].ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISABLE_SHIP_TACTICAL | AI_GOAL_DISARM_SHIP | AI_GOAL_DISARM_SHIP_TACTICAL)) && swip->wi_flags[Weapon::Info_Flags::Puncture] )) { //override lockdown on protected ships when using anti subsystem weapons - Valathil
|
||||
// If ship is protected and very low on hits, don't fire missiles.
|
||||
if (!(En_objp->flags[Object::Object_Flags::Protected]) || (En_objp->hull_strength > 10*swip->damage)) {
|
||||
if (aip->ai_flags[AI::AI_Flags::Unload_secondaries]) {
|
||||
|
||||
+112
-159
@@ -386,7 +386,7 @@ int is_preferred_weapon(int weapon_num, object *firer_objp, object *target_objp)
|
||||
continue;
|
||||
|
||||
auto ship_entry = &Ship_registry[hfi->ship_registry_index];
|
||||
if (ship_entry->status != ShipStatus::PRESENT)
|
||||
if (!ship_entry->objp)
|
||||
continue;
|
||||
|
||||
int signature = ship_entry->objp->signature;
|
||||
@@ -954,6 +954,21 @@ void ai_init()
|
||||
"ai autoscaling. If that's not desired then use a tbl instead of a tbm!\n"));
|
||||
}
|
||||
|
||||
// autoscaling is meaningless if only one AI class has it, and will produce either ineffectual or
|
||||
// divide-by-zero math expressions if $use adjusted AI class autoscale: is enabled
|
||||
int num_autoscaled_classes = 0;
|
||||
int autoscaled_class_index = -1;
|
||||
for (int i = 0; i < Num_ai_classes; ++i) {
|
||||
if (Ai_classes[i].ai_class_autoscale) {
|
||||
num_autoscaled_classes++;
|
||||
autoscaled_class_index = i;
|
||||
}
|
||||
}
|
||||
if (num_autoscaled_classes == 1) {
|
||||
Warning(LOCATION, "Autoscaling is meaningless when only one AI class has autoscaling enabled. Turning off autoscaling for %s.", Ai_classes[autoscaled_class_index].name);
|
||||
Ai_classes[autoscaled_class_index].ai_class_autoscale = false;
|
||||
}
|
||||
|
||||
atexit(free_ai_stuff);
|
||||
|
||||
ai_inited = 1;
|
||||
@@ -1301,7 +1316,7 @@ void ai_turn_towards_vector(vec3d* dest, object* objp, vec3d* slide_vec, vec3d*
|
||||
// Don't allow a ship to turn if it has no engine strength.
|
||||
// AL 3-12-98: objp may not always be a ship!
|
||||
if ( (objp->type == OBJ_SHIP) && !(flags & AITTV_VIA_SEXP) ) {
|
||||
if (ship_get_subsystem_strength(&Ships[objp->instance], SUBSYSTEM_ENGINE) <= 0.0f)
|
||||
if (!Ships[objp->instance].flags[Ship::Ship_Flags::Maneuver_despite_engines] && ship_get_subsystem_strength(&Ships[objp->instance], SUBSYSTEM_ENGINE) <= 0.0f)
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3447,36 +3462,6 @@ void ai_dock_with_object(object *docker, int docker_index, object *dockee, int d
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Cause a ship to fly toward a ship.
|
||||
*/
|
||||
void ai_start_fly_to_ship(object *objp, int shipnum)
|
||||
{
|
||||
ai_info *aip;
|
||||
|
||||
aip = &Ai_info[Ships[objp->instance].ai_index];
|
||||
|
||||
if (The_mission.flags[Mission::Mission_Flags::Use_ap_cinematics] && AutoPilotEngaged)
|
||||
{
|
||||
aip->ai_flags.remove(AI::AI_Flags::Formation_wing);
|
||||
}
|
||||
else
|
||||
{
|
||||
aip->ai_flags.set(AI::AI_Flags::Formation_wing);
|
||||
}
|
||||
aip->ai_flags.remove(AI::AI_Flags::Formation_object);
|
||||
|
||||
aip->mode = AIM_FLY_TO_SHIP;
|
||||
aip->submode_start_time = Missiontime;
|
||||
|
||||
aip->target_objnum = Ships[shipnum].objnum;
|
||||
// clear targeted subsystem
|
||||
set_targeted_subsys(aip, nullptr, -1);
|
||||
|
||||
Assert(aip->active_goal != AI_ACTIVE_GOAL_DYNAMIC);
|
||||
}
|
||||
|
||||
|
||||
// Cause a ship to fly its waypoints.
|
||||
// flags tells:
|
||||
// WPF_REPEAT Set -> repeat waypoints.
|
||||
@@ -3518,7 +3503,7 @@ void ai_start_waypoints(object *objp, waypoint_list *wp_list, int wp_flags)
|
||||
/**
|
||||
* Make *objp stay within dist units of *other_objp
|
||||
*/
|
||||
void ai_do_stay_near(object *objp, object *other_objp, float dist)
|
||||
void ai_do_stay_near(object *objp, object *other_objp, float dist, int additional_data)
|
||||
{
|
||||
ai_info *aip;
|
||||
|
||||
@@ -3531,7 +3516,8 @@ void ai_do_stay_near(object *objp, object *other_objp, float dist)
|
||||
aip->mode = AIM_STAY_NEAR;
|
||||
aip->submode = -1;
|
||||
aip->submode_start_time = Missiontime;
|
||||
aip->stay_near_distance = dist;
|
||||
aip->submode_float0 = dist;
|
||||
aip->submode_parm0 = additional_data;
|
||||
aip->goal_objnum = OBJ_INDEX(other_objp);
|
||||
aip->goal_signature = other_objp->signature;
|
||||
}
|
||||
@@ -4907,84 +4893,6 @@ void ai_waypoints()
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// make Pl_objp fly toward a ship
|
||||
void ai_fly_to_ship()
|
||||
{
|
||||
ai_info *aip;
|
||||
object* target_p = NULL;
|
||||
|
||||
aip = &Ai_info[Ships[Pl_objp->instance].ai_index];
|
||||
|
||||
if ( aip->mode != AIM_FLY_TO_SHIP ) {
|
||||
Warning(LOCATION,
|
||||
"ai_fly_to_ship called for '%s' when ai_info.mode not equal to AIM_FLY_TO_SHIP. Is actually '%d'",
|
||||
Ships[Pl_objp->instance].ship_name,
|
||||
aip->mode);
|
||||
aip->mode = AIM_NONE;
|
||||
return;
|
||||
}
|
||||
if ( aip->active_goal < 0 || aip->active_goal >= MAX_AI_GOALS ) {
|
||||
Warning(LOCATION,
|
||||
"'%s' is trying to fly-to a ship without an active AI_GOAL\n\n"
|
||||
"Active ai mode is '%d'",
|
||||
Ships[Pl_objp->instance].ship_name,
|
||||
aip->active_goal);
|
||||
aip->mode = AIM_NONE;
|
||||
return;
|
||||
}
|
||||
Assert( aip->goals[aip->active_goal].target_name != NULL );
|
||||
if ( aip->goals[aip->active_goal].target_name[0] == '\0' ) {
|
||||
Warning(LOCATION, "'%s' is trying to fly-to-ship without a name for the ship", Ships[Pl_objp->instance].ship_name);
|
||||
aip->mode = AIM_NONE;
|
||||
ai_remove_ship_goal( aip, aip->active_goal ); // function sets aip->active_goal to NONE for me
|
||||
return;
|
||||
}
|
||||
|
||||
for (int j = 0; j < MAX_SHIPS; j++)
|
||||
{
|
||||
if (Ships[j].objnum != -1 && !stricmp(aip->goals[aip->active_goal].target_name, Ships[j].ship_name))
|
||||
{
|
||||
target_p = &Objects[Ships[j].objnum];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( target_p == NULL ) {
|
||||
#ifndef NDEBUG
|
||||
for (int i = 0; i < MAX_AI_GOALS; i++)
|
||||
{
|
||||
if (aip->mode == AIM_FLY_TO_SHIP || aip->goals[i].ai_mode == AI_GOAL_FLY_TO_SHIP)
|
||||
{
|
||||
mprintf(("Ship '%s' told to fly to target ship '%s'\n",
|
||||
Ships[Pl_objp->instance].ship_name,
|
||||
aip->goals[i].target_name));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Warning(LOCATION, "Ship '%s' told to fly to a ship but none of the ships it was told to fly to exist.\n"
|
||||
"See log before this message for list of ships set as fly-to tagets",
|
||||
Ships[Pl_objp->instance].ship_name);
|
||||
aip->mode = AIM_NONE;
|
||||
ai_remove_ship_goal( aip, aip->active_goal ); // function sets aip->active_goal to NONE for me
|
||||
return;
|
||||
} else {
|
||||
bool done, treat_as_ship;
|
||||
ai_fly_to_target_position(&(target_p->pos), &done, &treat_as_ship);
|
||||
|
||||
if ( done ) {
|
||||
// remove the goal from the AI goals of the ship pr wing, respectively.
|
||||
// Wether or not we should treat this as a ship or a wing is determined by
|
||||
// ai_fly_to_target when it marks the AI directive as complete
|
||||
if ( treat_as_ship ) {
|
||||
ai_mission_goal_complete( aip ); // this call should reset the AI mode
|
||||
} else {
|
||||
ai_mission_wing_goal_complete( Ships[Pl_objp->instance].wingnum, &(aip->goals[aip->active_goal]) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make Pl_objp avoid En_objp
|
||||
// Not like evading. This is for avoiding a collision!
|
||||
// Note, use sliding if available.
|
||||
@@ -5656,7 +5564,7 @@ int ai_select_primary_weapon(object *objp, object *other_objp, Weapon::Info_Flag
|
||||
Assert( shipp->ship_info_index >= 0 && shipp->ship_info_index < ship_info_size());
|
||||
|
||||
//made it so it only selects puncture weapons if the active goal is to disable something -Bobboau
|
||||
if ((flags == Weapon::Info_Flags::Puncture) && (Ai_info[shipp->ai_index].goals[0].ai_mode & (AI_GOAL_DISARM_SHIP | AI_GOAL_DISABLE_SHIP)))
|
||||
if ((flags == Weapon::Info_Flags::Puncture) && (Ai_info[shipp->ai_index].goals[0].ai_mode & (AI_GOAL_DISARM_SHIP | AI_GOAL_DISARM_SHIP_TACTICAL | AI_GOAL_DISABLE_SHIP | AI_GOAL_DISABLE_SHIP_TACTICAL)))
|
||||
{
|
||||
if (swp->current_primary_bank >= 0)
|
||||
{
|
||||
@@ -5881,7 +5789,7 @@ void set_primary_weapon_linkage(object *objp)
|
||||
// puncture weapons
|
||||
if ( (aip->active_goal != AI_GOAL_NONE) && (aip->active_goal != AI_ACTIVE_GOAL_DYNAMIC) )
|
||||
{
|
||||
if ( aip->goals[aip->active_goal].ai_mode & (AI_GOAL_DISABLE_SHIP|AI_GOAL_DISARM_SHIP) )
|
||||
if ( aip->goals[aip->active_goal].ai_mode & (AI_GOAL_DISABLE_SHIP|AI_GOAL_DISABLE_SHIP_TACTICAL|AI_GOAL_DISARM_SHIP|AI_GOAL_DISARM_SHIP_TACTICAL) )
|
||||
{
|
||||
// only continue if both primaries are puncture weapons
|
||||
if ( swp->num_primary_banks == 2 ) {
|
||||
@@ -9471,9 +9379,15 @@ void ai_chase()
|
||||
firing_range = MIN((swip->max_speed * swip->lifetime * 0.75f), swip->weapon_range);
|
||||
else
|
||||
{
|
||||
float secondary_range_mult = (aip->ai_secondary_range_mult == FLT_MIN)
|
||||
? (float)(Game_skill_level + 1 + (3 * ai_maybe_autoscale(aip->ai_class)/(ai_maybe_autoscale(Num_ai_classes) - 1)))/NUM_SKILL_LEVELS
|
||||
: aip->ai_secondary_range_mult;
|
||||
float secondary_range_mult;
|
||||
|
||||
// Cyborg: need to check for division by zero, coverity 1523419
|
||||
if (aip->ai_secondary_range_mult == FLT_MIN && (ai_maybe_autoscale(Num_ai_classes) > 1))
|
||||
secondary_range_mult = (float)(Game_skill_level + 1 + (3 * ai_maybe_autoscale(aip->ai_class)/(ai_maybe_autoscale(Num_ai_classes) - 1)))/NUM_SKILL_LEVELS;
|
||||
else if (aip->ai_secondary_range_mult == FLT_MIN)
|
||||
secondary_range_mult = (float)(Game_skill_level + 2)/NUM_SKILL_LEVELS; // default to using the default retail class Captain out of the seven there are total when we don't have enough autoscale classes or just one regular class. (This simplifies to 2 + Game_skill_level / Num of skill levels)
|
||||
else
|
||||
secondary_range_mult = aip->ai_secondary_range_mult;
|
||||
|
||||
firing_range = MIN((swip->max_speed * swip->lifetime * secondary_range_mult), swip->weapon_range);
|
||||
}
|
||||
@@ -9776,7 +9690,7 @@ float dock_orient_and_approach(object *docker_objp, int docker_index, object *do
|
||||
|
||||
// Goober5000 - moved out here to save calculations
|
||||
if (dock_mode != DOA_DOCK_STAY)
|
||||
if (ship_get_subsystem_strength(&Ships[docker_objp->instance], SUBSYSTEM_ENGINE) <= 0.0f)
|
||||
if (!Ships[docker_objp->instance].flags[Ship::Ship_Flags::Maneuver_despite_engines] && ship_get_subsystem_strength(&Ships[docker_objp->instance], SUBSYSTEM_ENGINE) <= 0.0f)
|
||||
return 9999.9f;
|
||||
|
||||
// If dockee has moved much, then path will be recreated.
|
||||
@@ -11342,24 +11256,52 @@ void ai_still()
|
||||
// Make *Pl_objp stay near another ship.
|
||||
void ai_stay_near()
|
||||
{
|
||||
ai_info *aip;
|
||||
int goal_objnum;
|
||||
|
||||
aip = &Ai_info[Ships[Pl_objp->instance].ai_index];
|
||||
|
||||
goal_objnum = aip->goal_objnum;
|
||||
auto aip = &Ai_info[Ships[Pl_objp->instance].ai_index];
|
||||
int goal_objnum = aip->goal_objnum;
|
||||
|
||||
if ((goal_objnum < 0) || (Objects[goal_objnum].type != OBJ_SHIP) || (Objects[goal_objnum].signature != aip->goal_signature)) {
|
||||
aip->mode = AIM_NONE;
|
||||
} else {
|
||||
float dist, max_dist, scale;
|
||||
vec3d rand_vec, goal_pos, vec_to_goal;
|
||||
object *goal_objp;
|
||||
}
|
||||
// "escort" behavior
|
||||
else if (aip->submode_parm0 != 0) {
|
||||
vec3d rand_vec, center_to_goal, center_to_objp;
|
||||
auto goal_objp = &Objects[goal_objnum];
|
||||
float max_dist = aip->submode_float0;
|
||||
|
||||
goal_objp = &Objects[goal_objnum];
|
||||
// Figure out a goal point to fly to
|
||||
// Make not all ships pursue same point.
|
||||
// Calculate the seed from both shipnums so the same Pl_objp doesn't always choose the same spot
|
||||
static_randvec((goal_objp->instance * MAX_SHIPS) + (Pl_objp->instance), &rand_vec);
|
||||
aip->goal_point = goal_objp->pos + max_dist * rand_vec;
|
||||
|
||||
// Make sure point is on the near side of goal_objp (relative to Pl_objp's position).
|
||||
center_to_goal = aip->goal_point - goal_objp->pos;
|
||||
center_to_objp = Pl_objp->pos - goal_objp->pos;
|
||||
if (vm_vec_dot(¢er_to_goal, ¢er_to_objp) < 0.0f) {
|
||||
vm_vec_negate(&rand_vec);
|
||||
aip->goal_point = goal_objp->pos + max_dist * rand_vec;
|
||||
}
|
||||
|
||||
// Fly to the point
|
||||
auto dist = vm_vec_dist_quick(&goal_objp->pos, &Pl_objp->pos);
|
||||
if (dist > max_dist) {
|
||||
turn_towards_point(Pl_objp, &aip->goal_point, nullptr, 0.0f);
|
||||
accelerate_ship(aip, dist / max_dist - 0.8f);
|
||||
|
||||
float dot = vm_vec_dot_to_point(&Pl_objp->orient.vec.fvec, &Pl_objp->pos, &aip->goal_point);
|
||||
if (ai_willing_to_afterburn_hard(aip) && dot > 0.99f && dist - max_dist > 700.0f)
|
||||
ai_afterburn_hard(Pl_objp, aip);
|
||||
}
|
||||
}
|
||||
// standard behavior
|
||||
else {
|
||||
vec3d rand_vec, goal_pos, vec_to_goal;
|
||||
auto goal_objp = &Objects[goal_objnum];
|
||||
float max_dist = aip->submode_float0;
|
||||
|
||||
// Make not all ships pursue same point.
|
||||
static_randvec(OBJ_INDEX(Pl_objp), &rand_vec);
|
||||
// Calculate the seed from both shipnums so the same Pl_objp doesn't always choose the same spot
|
||||
static_randvec((goal_objp->instance * MAX_SHIPS) + (Pl_objp->instance), &rand_vec);
|
||||
|
||||
// Make sure point is in front hemisphere (relative to Pl_objp's position.
|
||||
vm_vec_sub(&vec_to_goal, &goal_objp->pos, &Pl_objp->pos);
|
||||
@@ -11368,28 +11310,22 @@ void ai_stay_near()
|
||||
}
|
||||
|
||||
// Scale the random vector by an amount proportional to the distance from Pl_objp to the true goal.
|
||||
dist = vm_vec_dist_quick(&goal_objp->pos, &Pl_objp->pos);
|
||||
max_dist = aip->stay_near_distance;
|
||||
scale = dist - max_dist/2;
|
||||
float dist = vm_vec_dist_quick(&goal_objp->pos, &Pl_objp->pos);
|
||||
float scale = dist - max_dist/2;
|
||||
if (scale < 0.0f)
|
||||
scale = 0.0f;
|
||||
|
||||
vm_vec_scale_add(&goal_pos, &goal_objp->pos, &rand_vec, scale);
|
||||
|
||||
if (max_dist < Pl_objp->radius + goal_objp->radius + 25.0f)
|
||||
max_dist = Pl_objp->radius + goal_objp->radius + 25.0f;
|
||||
|
||||
// Fly to the point
|
||||
if (dist > max_dist) {
|
||||
turn_towards_point(Pl_objp, &goal_pos, NULL, 0.0f);
|
||||
turn_towards_point(Pl_objp, &goal_pos, nullptr, 0.0f);
|
||||
accelerate_ship(aip, dist / max_dist - 0.8f);
|
||||
|
||||
float dot = vm_vec_dot_to_point(&Pl_objp->orient.vec.fvec, &Pl_objp->pos, &goal_pos);
|
||||
if (ai_willing_to_afterburn_hard(aip) && dot > 0.99f && dist - max_dist > 700.0f)
|
||||
ai_afterburn_hard(Pl_objp, aip);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Warn player if dock path is obstructed.
|
||||
@@ -12141,7 +12077,7 @@ object *get_wing_leader(int wingnum)
|
||||
|
||||
// If this ship is disabled, try another ship in the wing.
|
||||
int n = 0;
|
||||
while (ship_get_subsystem_strength(&Ships[ship_num], SUBSYSTEM_ENGINE) == 0.0f) {
|
||||
while (!Ships[ship_num].flags[Ship::Ship_Flags::Maneuver_despite_engines] && ship_get_subsystem_strength(&Ships[ship_num], SUBSYSTEM_ENGINE) == 0.0f) {
|
||||
n++;
|
||||
|
||||
if (n >= wingp->current_count) {
|
||||
@@ -12484,7 +12420,7 @@ int ai_formation()
|
||||
} else { // Formation flying in waypoint mode.
|
||||
Assert(aip->ai_flags[AI::AI_Flags::Formation_wing]);
|
||||
|
||||
if ( (aip->mode != AIM_WAYPOINTS) && (aip->mode != AIM_FLY_TO_SHIP) ) {
|
||||
if ( aip->mode != AIM_WAYPOINTS ) {
|
||||
aip->ai_flags.remove(AI::AI_Flags::Formation_wing);
|
||||
return 1;
|
||||
}
|
||||
@@ -13114,10 +13050,25 @@ void ai_manage_shield(object *objp, ai_info *aip)
|
||||
// Scale between 1x and 3x based on ai_class (SUSHI: only if autoscale is on)
|
||||
if (aip->ai_class_autoscale)
|
||||
{
|
||||
if (The_mission.ai_profile->flags[AI::Profile_Flags::Adjusted_AI_class_autoscale])
|
||||
delay = delay + delay * (float)(3 * (ai_get_autoscale_index(Num_ai_classes) - ai_get_autoscale_index(aip->ai_class) - 1) / (ai_get_autoscale_index(Num_ai_classes) - 1));
|
||||
else
|
||||
delay = delay + delay * (float)(3 * (Num_ai_classes - aip->ai_class - 1) / (Num_ai_classes - 1));
|
||||
int number_of_as_classes = ai_get_autoscale_index(Num_ai_classes);
|
||||
|
||||
// Cyborg: Make sure that autoscale index is greater than one before dividing, coverity 1523548
|
||||
if (The_mission.ai_profile->flags[AI::Profile_Flags::Adjusted_AI_class_autoscale] && number_of_as_classes > 1)
|
||||
delay = delay + delay * (float)(3 * (number_of_as_classes - ai_get_autoscale_index(aip->ai_class) - 1) / (number_of_as_classes - 1));
|
||||
else {
|
||||
static bool autoscale_checked = false;
|
||||
|
||||
// warn if there's only one autoscale ai class
|
||||
if (number_of_as_classes == 1 && !autoscale_checked) {
|
||||
mprintf(("Warning! Having only 1 autoscale ai class will disable autoscale features that rely on division."));
|
||||
autoscale_checked = true;
|
||||
}
|
||||
|
||||
// Only adjust if we have more than one ai class to avoid div by 0
|
||||
if (Num_ai_classes > 1){
|
||||
delay = delay + delay * (float)(3 * (Num_ai_classes - aip->ai_class - 1) / (Num_ai_classes - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set timestamp
|
||||
@@ -13487,8 +13438,14 @@ int ai_acquire_emerge_path(object *pl_objp, int parent_objnum, int allowed_path_
|
||||
}
|
||||
}
|
||||
|
||||
// cycle through the allowed paths
|
||||
bay_path = allowed_bay_paths[Ai_last_arrive_path % num_allowed_paths];
|
||||
// Cyborg: to avoid divide by zero and avoid a logic path that should not exist check for 0 allowed paths -- Coverity 1523287
|
||||
if (num_allowed_paths == 0) {
|
||||
bay_path = Ai_last_arrive_path % bay->num_paths;
|
||||
UNREACHABLE("Parent_shipp in ai_acquire_emerge_path somehow does not have any allowed bay paths!");
|
||||
} else {
|
||||
// cycle through the allowed paths
|
||||
bay_path = allowed_bay_paths[Ai_last_arrive_path % num_allowed_paths];
|
||||
}
|
||||
}
|
||||
// choose from among all paths
|
||||
else
|
||||
@@ -13906,6 +13863,7 @@ void ai_execute_behavior(ai_info *aip)
|
||||
case AIM_STILL:
|
||||
ai_still();
|
||||
break;
|
||||
case AIM_FLY_TO_SHIP: // same code as stay-near
|
||||
case AIM_STAY_NEAR:
|
||||
ai_stay_near();
|
||||
break;
|
||||
@@ -13915,9 +13873,6 @@ void ai_execute_behavior(ai_info *aip)
|
||||
case AIM_WAYPOINTS:
|
||||
ai_waypoints();
|
||||
break;
|
||||
case AIM_FLY_TO_SHIP:
|
||||
ai_fly_to_ship();
|
||||
break;
|
||||
case AIM_DOCK:
|
||||
ai_dock();
|
||||
break;
|
||||
@@ -14884,7 +14839,7 @@ void ai_frame(int objnum)
|
||||
aip->ai_flags.remove(AI::AI_Flags::Avoid_shockwave_started);
|
||||
}
|
||||
|
||||
// moved call to ai_do_repair frame here from below because of the subsequent if statment returning
|
||||
// moved call to ai_do_repair frame here from below because of the subsequent if statement returning
|
||||
// if the ship is getting repaired
|
||||
// If waiting to be repaired, just stop and sit.
|
||||
ai_do_repair_frame(Pl_objp, aip, flFrametime);
|
||||
@@ -15006,9 +14961,9 @@ void ai_frame(int objnum)
|
||||
if ( aip->targeted_subsys->current_hits <= 0.0f ) {
|
||||
int subsys_type;
|
||||
|
||||
if ( aip->goals[0].ai_mode == AI_GOAL_DISABLE_SHIP ) {
|
||||
if ( aip->goals[0].ai_mode == AI_GOAL_DISABLE_SHIP || aip->goals[0].ai_mode == AI_GOAL_DISABLE_SHIP_TACTICAL ) {
|
||||
subsys_type = SUBSYSTEM_ENGINE;
|
||||
} else if ( aip->goals[0].ai_mode == AI_GOAL_DISARM_SHIP ) {
|
||||
} else if ( aip->goals[0].ai_mode == AI_GOAL_DISARM_SHIP || aip->goals[0].ai_mode == AI_GOAL_DISARM_SHIP_TACTICAL ) {
|
||||
subsys_type = SUBSYSTEM_TURRET;
|
||||
} else {
|
||||
subsys_type = -1;
|
||||
@@ -15264,6 +15219,7 @@ void init_ai_object(int objnum)
|
||||
aip->submode_start_time = 0;
|
||||
aip->submode_parm0 = 0;
|
||||
aip->submode_parm1 = 0;
|
||||
aip->submode_float0 = 0.0f;
|
||||
aip->active_goal = -1;
|
||||
aip->goal_check_time = timestamp(0);
|
||||
aip->last_predicted_enemy_pos = near_vec;
|
||||
@@ -16073,22 +16029,19 @@ void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hit_normal)
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case AIM_FLY_TO_SHIP:
|
||||
case AIM_WAYPOINTS:
|
||||
if (sip->is_fighter_bomber())
|
||||
break;
|
||||
else
|
||||
return;
|
||||
break;
|
||||
return;
|
||||
case AIM_SAFETY:
|
||||
if ((aip->submode != AISS_1) || (Missiontime - aip->submode_start_time > i2f(1))) {
|
||||
aip->submode = AISS_1;
|
||||
aip->submode_start_time = Missiontime;
|
||||
}
|
||||
return;
|
||||
break;
|
||||
case AIM_WARP_OUT:
|
||||
return;
|
||||
break;
|
||||
case AIM_LUA:
|
||||
return;
|
||||
default:
|
||||
|
||||
+167
-135
@@ -51,6 +51,8 @@ struct ship_registry_entry;
|
||||
// Goober5000 - okay, this seems really stupid. If any ship in the mission is assigned a goal
|
||||
// in PURGE_GOALS_ALL_SHIPS, *every* other ship will have certain goals purged. So I added
|
||||
// PURGE_GOALS_ONE_SHIP for goals which should only purge other goals in the one ship.
|
||||
// Goober5000 - note that the new disable and disarm goals (AI_GOAL_DISABLE_SHIP_TACTICAL and
|
||||
// AI_GOAL_DISARM_SHIP_TACTICAL) do not purge ANY goals, not even the ones in the one ship
|
||||
#define PURGE_GOALS_ALL_SHIPS (AI_GOAL_IGNORE | AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP)
|
||||
#define PURGE_GOALS_ONE_SHIP (AI_GOAL_IGNORE_NEW)
|
||||
|
||||
@@ -75,7 +77,9 @@ ai_goal_list Ai_goal_names[] =
|
||||
{ "Attack wing", AI_GOAL_CHASE_WING, 0 },
|
||||
{ "Guard ship", AI_GOAL_GUARD, 0 },
|
||||
{ "Disable ship", AI_GOAL_DISABLE_SHIP, 0 },
|
||||
{ "Disable ship (tactical)",AI_GOAL_DISABLE_SHIP_TACTICAL, 0 },
|
||||
{ "Disarm ship", AI_GOAL_DISARM_SHIP, 0 },
|
||||
{ "Disarm ship (tactical)", AI_GOAL_DISARM_SHIP_TACTICAL, 0 },
|
||||
{ "Attack any", AI_GOAL_CHASE_ANY, 0 },
|
||||
{ "Ignore ship", AI_GOAL_IGNORE, 0 },
|
||||
{ "Ignore ship (new)", AI_GOAL_IGNORE_NEW, 0 },
|
||||
@@ -120,8 +124,10 @@ const char *Ai_goal_text(int goal, int submode)
|
||||
case AI_GOAL_GUARD_WING:
|
||||
return XSTR( "guard ", 480);
|
||||
case AI_GOAL_DISABLE_SHIP:
|
||||
case AI_GOAL_DISABLE_SHIP_TACTICAL:
|
||||
return XSTR( "disable ", 481);
|
||||
case AI_GOAL_DISARM_SHIP:
|
||||
case AI_GOAL_DISARM_SHIP_TACTICAL:
|
||||
return XSTR( "disarm ", 482);
|
||||
case AI_GOAL_EVADE_SHIP:
|
||||
return XSTR( "evade ", 483);
|
||||
@@ -528,11 +534,12 @@ void ai_goal_purge_invalid_goals( ai_goal *aigp, ai_goal *goal_list, ai_info *ai
|
||||
// ignore goals should get rid of any kind of attack goal
|
||||
case AI_GOAL_IGNORE:
|
||||
case AI_GOAL_IGNORE_NEW:
|
||||
if ( purge_ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP | AI_GOAL_CHASE | AI_GOAL_CHASE_WING | AI_GOAL_CHASE_SHIP_CLASS | AI_GOAL_DESTROY_SUBSYSTEM) )
|
||||
if ( purge_ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISABLE_SHIP_TACTICAL | AI_GOAL_DISARM_SHIP | AI_GOAL_DISARM_SHIP_TACTICAL | AI_GOAL_CHASE | AI_GOAL_CHASE_WING | AI_GOAL_CHASE_SHIP_CLASS | AI_GOAL_DESTROY_SUBSYSTEM) )
|
||||
purge_goal->flags.set(AI::Goal_Flags::Purge);
|
||||
break;
|
||||
|
||||
// disarm/disable goals should remove attacks from certain ships types
|
||||
// (but not tactical disarm/disable)
|
||||
case AI_GOAL_DISARM_SHIP:
|
||||
case AI_GOAL_DISABLE_SHIP:
|
||||
if ( purge_ai_mode & (AI_GOAL_CHASE | AI_GOAL_CHASE_WING | AI_GOAL_CHASE_SHIP_CLASS) ) {
|
||||
@@ -549,12 +556,17 @@ void ai_goal_purge_invalid_goals( ai_goal *aigp, ai_goal *goal_list, ai_info *ai
|
||||
}
|
||||
|
||||
// grab the ship type of the ship that is being disarmed/disabled
|
||||
ship_type_info *crippled_ships_type = &Ship_types[Ship_info[Ships[ship_index].ship_info_index].class_type];
|
||||
int crippled_ship_type = Ship_info[Ships[ship_index].ship_info_index].class_type;
|
||||
|
||||
// work through all the ship types which to see if the class matching our ai ship must ignore the ship
|
||||
if (ai_ship_type < 0 || crippled_ship_type < 0)
|
||||
break;
|
||||
|
||||
ship_type_info *crippled_ship_type_info = &Ship_types[crippled_ship_type];
|
||||
|
||||
// work through all the ship types to see if the class matching our ai ship must ignore the ship
|
||||
// being disarmed/disabled
|
||||
for ( j=0 ; j < (int)crippled_ships_type->ai_cripple_ignores.size(); j++) {
|
||||
if (crippled_ships_type->ai_cripple_ignores[j] == ai_ship_type) {
|
||||
for ( j=0 ; j < (int)crippled_ship_type_info->ai_cripple_ignores.size(); j++) {
|
||||
if (crippled_ship_type_info->ai_cripple_ignores[j] == ai_ship_type) {
|
||||
purge_goal->flags.set(AI::Goal_Flags::Purge);
|
||||
}
|
||||
}
|
||||
@@ -931,14 +943,16 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, char
|
||||
break;
|
||||
|
||||
case OP_AI_DISABLE_SHIP:
|
||||
aigp->ai_mode = AI_GOAL_DISABLE_SHIP;
|
||||
case OP_AI_DISABLE_SHIP_TACTICAL:
|
||||
aigp->ai_mode = (op == OP_AI_DISABLE_SHIP) ? AI_GOAL_DISABLE_SHIP : AI_GOAL_DISABLE_SHIP_TACTICAL;
|
||||
aigp->target_name = ai_get_goal_target_name( CTEXT(CDR(node)), &aigp->target_name_index );
|
||||
aigp->ai_submode = -SUBSYSTEM_ENGINE;
|
||||
aigp->priority = atoi( CTEXT(CDR(CDR(node))) );
|
||||
break;
|
||||
|
||||
case OP_AI_DISARM_SHIP:
|
||||
aigp->ai_mode = AI_GOAL_DISARM_SHIP;
|
||||
case OP_AI_DISARM_SHIP_TACTICAL:
|
||||
aigp->ai_mode = (op == OP_AI_DISARM_SHIP) ? AI_GOAL_DISARM_SHIP : AI_GOAL_DISARM_SHIP_TACTICAL;
|
||||
aigp->target_name = ai_get_goal_target_name( CTEXT(CDR(node)), &aigp->target_name_index );
|
||||
aigp->ai_submode = -SUBSYSTEM_TURRET;
|
||||
aigp->priority = atoi( CTEXT(CDR(CDR(node))) );
|
||||
@@ -976,7 +990,7 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, char
|
||||
// this goal needs some extra setup
|
||||
// if this doesn't work, the goal will be immediately removed
|
||||
auto ship_entry = ship_registry_get(aigp->target_name);
|
||||
if (ship_entry->status == ShipStatus::PRESENT)
|
||||
if (ship_entry && ship_entry->shipp)
|
||||
{
|
||||
auto target_aip = &Ai_info[ship_entry->shipp->ai_index];
|
||||
target_aip->ai_flags.set(AI::AI_Flags::Awaiting_repair);
|
||||
@@ -1022,15 +1036,32 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, char
|
||||
aigp->ai_mode = AI_GOAL_KEEP_SAFE_DISTANCE;
|
||||
break;
|
||||
|
||||
case OP_AI_FLY_TO_SHIP:
|
||||
case OP_AI_STAY_NEAR_SHIP:
|
||||
{
|
||||
bool is_nan, is_nan_forever;
|
||||
|
||||
aigp->target_name = ai_get_goal_target_name( CTEXT(CDR(node)), &aigp->target_name_index );
|
||||
aigp->priority = atoi( CTEXT(CDDR(node)) );
|
||||
|
||||
// distance from ship
|
||||
if ( CDDDR(node) < 0 )
|
||||
aigp->float_data = 300.0f;
|
||||
else
|
||||
aigp->float_data = i2fl(atoi( CTEXT(CDDDR(node)) ));
|
||||
aigp->ai_mode = AI_GOAL_STAY_NEAR_SHIP;
|
||||
aigp->float_data = i2fl(eval_num(CDDDR(node), is_nan, is_nan_forever));
|
||||
|
||||
// (the CDDDDR argument is whether to afterburn, and is handled at the end of the function, so don't handle it here)
|
||||
|
||||
// whether to "escort" the ship
|
||||
if ( CDDDDDR(node) >= 0 )
|
||||
aigp->int_data = is_sexp_true(CDDDDDR(node)) ? 1 : 0;
|
||||
|
||||
if (op == OP_AI_FLY_TO_SHIP)
|
||||
aigp->ai_mode = AI_GOAL_FLY_TO_SHIP;
|
||||
else
|
||||
aigp->ai_mode = AI_GOAL_STAY_NEAR_SHIP;
|
||||
break;
|
||||
}
|
||||
|
||||
case OP_AI_FORM_ON_WING:
|
||||
aigp->priority = 99;
|
||||
@@ -1046,7 +1077,6 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, char
|
||||
case OP_AI_EVADE_SHIP:
|
||||
case OP_AI_IGNORE:
|
||||
case OP_AI_IGNORE_NEW:
|
||||
case OP_AI_FLY_TO_SHIP:
|
||||
aigp->target_name = ai_get_goal_target_name( CTEXT(CDR(node)), &aigp->target_name_index );
|
||||
aigp->priority = atoi( CTEXT(CDR(CDR(node))) );
|
||||
|
||||
@@ -1073,14 +1103,10 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, char
|
||||
aigp->ai_mode = AI_GOAL_CHASE_WING;
|
||||
} else if (op == OP_AI_CHASE_SHIP_CLASS) {
|
||||
aigp->ai_mode = AI_GOAL_CHASE_SHIP_CLASS;
|
||||
} else if ( op == OP_AI_STAY_NEAR_SHIP ) {
|
||||
aigp->ai_mode = AI_GOAL_STAY_NEAR_SHIP;
|
||||
} else if ( op == OP_AI_IGNORE ) {
|
||||
aigp->ai_mode = AI_GOAL_IGNORE;
|
||||
} else if ( op == OP_AI_IGNORE_NEW ) {
|
||||
aigp->ai_mode = AI_GOAL_IGNORE_NEW;
|
||||
} else if ( op == OP_AI_FLY_TO_SHIP ) {
|
||||
aigp->ai_mode = AI_GOAL_FLY_TO_SHIP;
|
||||
} else
|
||||
UNREACHABLE("Coding error: unhandled AI goal in ai_add_goal_sub_sexp!");
|
||||
|
||||
@@ -1117,39 +1143,42 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_info *aip, ai_goal *aigp, char
|
||||
}
|
||||
|
||||
// Goober5000 - we now have an extra optional chase argument to allow chasing our own team
|
||||
if ( op == OP_AI_CHASE || op == OP_AI_CHASE_WING || op == OP_AI_CHASE_SHIP_CLASS || op == OP_AI_DISABLE_SHIP || op == OP_AI_DISARM_SHIP ) {
|
||||
if ((CDDDR(node) != -1) && is_sexp_true(CDDDR(node)))
|
||||
if ( op == OP_AI_CHASE || op == OP_AI_CHASE_WING || op == OP_AI_CHASE_SHIP_CLASS
|
||||
|| op == OP_AI_DISABLE_SHIP || op == OP_AI_DISABLE_SHIP_TACTICAL || op == OP_AI_DISARM_SHIP || op == OP_AI_DISARM_SHIP_TACTICAL ) {
|
||||
if (is_sexp_true(CDDDR(node)))
|
||||
aigp->flags.set(AI::Goal_Flags::Target_own_team);
|
||||
}
|
||||
if ( op == OP_AI_DESTROY_SUBSYS ) {
|
||||
if ((CDDDDR(node) != -1) && is_sexp_true(CDDDDR(node)))
|
||||
if (is_sexp_true(CDDDDR(node)))
|
||||
aigp->flags.set(AI::Goal_Flags::Target_own_team);
|
||||
}
|
||||
|
||||
// maybe get the afterburn hard flag
|
||||
if (op == OP_AI_CHASE_ANY) {
|
||||
if ((CDDR(node) != -1) && is_sexp_true(CDDR(node)))
|
||||
if (is_sexp_true(CDDR(node)))
|
||||
aigp->flags.set(AI::Goal_Flags::Afterburn_hard);
|
||||
}
|
||||
if (op == OP_AI_GUARD ||
|
||||
op == OP_AI_GUARD_WING ||
|
||||
op == OP_AI_WAYPOINTS ||
|
||||
op == OP_AI_WAYPOINTS_ONCE ||
|
||||
op == OP_AI_FLY_TO_SHIP) {
|
||||
if ((CDDDR(node) != -1) && is_sexp_true(CDDDR(node)))
|
||||
op == OP_AI_WAYPOINTS_ONCE) {
|
||||
if (is_sexp_true(CDDDR(node)))
|
||||
aigp->flags.set(AI::Goal_Flags::Afterburn_hard);
|
||||
}
|
||||
if (op == OP_AI_CHASE ||
|
||||
op == OP_AI_CHASE_WING ||
|
||||
op == OP_AI_CHASE_SHIP_CLASS ||
|
||||
op == OP_AI_DISABLE_SHIP ||
|
||||
op == OP_AI_DISABLE_SHIP_TACTICAL ||
|
||||
op == OP_AI_DISARM_SHIP ||
|
||||
op == OP_AI_STAY_NEAR_SHIP) {
|
||||
if ((CDDDDR(node) != -1) && is_sexp_true(CDDDDR(node)))
|
||||
op == OP_AI_DISARM_SHIP_TACTICAL ||
|
||||
op == OP_AI_STAY_NEAR_SHIP ||
|
||||
op == OP_AI_FLY_TO_SHIP) {
|
||||
if (is_sexp_true(CDDDDR(node)))
|
||||
aigp->flags.set(AI::Goal_Flags::Afterburn_hard);
|
||||
}
|
||||
if (op == OP_AI_DESTROY_SUBSYS || op == OP_AI_DOCK) {
|
||||
if ((CDDDDDR(node) != -1) && is_sexp_true(CDDDDDR(node)))
|
||||
if (is_sexp_true(CDDDDDR(node)))
|
||||
aigp->flags.set(AI::Goal_Flags::Afterburn_hard);
|
||||
}
|
||||
|
||||
@@ -1219,11 +1248,13 @@ int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp )
|
||||
priority = ( CDR( CDR( CDR(node) ) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( CDR( node ) ) ) ) ) : -1;
|
||||
break;
|
||||
case OP_AI_DISABLE_SHIP:
|
||||
goalmode = AI_GOAL_DISABLE_SHIP;
|
||||
case OP_AI_DISABLE_SHIP_TACTICAL:
|
||||
goalmode = (op == OP_AI_DISABLE_SHIP) ? AI_GOAL_DISABLE_SHIP : AI_GOAL_DISABLE_SHIP_TACTICAL;
|
||||
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
|
||||
break;
|
||||
case OP_AI_DISARM_SHIP:
|
||||
goalmode = AI_GOAL_DISABLE_SHIP;
|
||||
case OP_AI_DISARM_SHIP_TACTICAL:
|
||||
goalmode = (op == OP_AI_DISARM_SHIP) ? AI_GOAL_DISARM_SHIP : AI_GOAL_DISARM_SHIP_TACTICAL;
|
||||
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
|
||||
break;
|
||||
case OP_AI_WARP_OUT:
|
||||
@@ -1253,11 +1284,8 @@ int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp )
|
||||
priority = ( CDR(node) >= 0 ) ? atoi( CTEXT( CDR( node ) ) ) : -1;
|
||||
break;
|
||||
case OP_AI_PLAY_DEAD:
|
||||
goalmode = AI_GOAL_PLAY_DEAD;
|
||||
priority = ( CDR(node) >= 0 ) ? atoi( CTEXT( CDR( node ) ) ) : -1;
|
||||
break;
|
||||
case OP_AI_PLAY_DEAD_PERSISTENT:
|
||||
goalmode = AI_GOAL_PLAY_DEAD_PERSISTENT;
|
||||
goalmode = (op == OP_AI_PLAY_DEAD) ? AI_GOAL_PLAY_DEAD : AI_GOAL_PLAY_DEAD_PERSISTENT;
|
||||
priority = ( CDR(node) >= 0 ) ? atoi( CTEXT( CDR( node ) ) ) : -1;
|
||||
break;
|
||||
case OP_AI_KEEP_SAFE_DISTANCE:
|
||||
@@ -1299,12 +1327,9 @@ int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp )
|
||||
goalmode = AI_GOAL_STAY_NEAR_SHIP;
|
||||
break;
|
||||
case OP_AI_IGNORE:
|
||||
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
|
||||
goalmode = AI_GOAL_IGNORE;
|
||||
break;
|
||||
case OP_AI_IGNORE_NEW:
|
||||
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
|
||||
goalmode = AI_GOAL_IGNORE_NEW;
|
||||
goalmode = (op == OP_AI_IGNORE) ? AI_GOAL_IGNORE : AI_GOAL_IGNORE_NEW;
|
||||
break;
|
||||
case OP_AI_FORM_ON_WING:
|
||||
priority = 99;
|
||||
@@ -1526,13 +1551,11 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
{
|
||||
int status;
|
||||
ai_achievability return_val;
|
||||
ai_info *aip;
|
||||
int index = -1, sindex = -1;
|
||||
int modelnum = -1;
|
||||
|
||||
auto objp = &Objects[objnum];
|
||||
Assert( objp->instance != -1 );
|
||||
aip = &Ai_info[Ships[objp->instance].ai_index];
|
||||
auto shipp = &Ships[objp->instance];
|
||||
auto aip = &Ai_info[shipp->ai_index];
|
||||
|
||||
// these orders are always achievable.
|
||||
if ( (aigp->ai_mode == AI_GOAL_KEEP_SAFE_DISTANCE)
|
||||
@@ -1543,11 +1566,11 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
if (aigp->ai_mode == AI_GOAL_LUA)
|
||||
return ai_lua_is_achievable(aigp, objnum);
|
||||
|
||||
auto target_ship_entry = aigp->target_name == nullptr ? nullptr : ship_registry_get(aigp->target_name);
|
||||
|
||||
// warp (depart) only achievable if there's somewhere to depart to
|
||||
if (aigp->ai_mode == AI_GOAL_WARP)
|
||||
{
|
||||
ship *shipp = &Ships[objp->instance];
|
||||
|
||||
// always valid if has working subspace drive, not disabled, and not limited by subsystem strength
|
||||
if ( ship_can_warp_full_check(shipp) )
|
||||
return ai_achievability::ACHIEVABLE;
|
||||
@@ -1566,9 +1589,7 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
// if the wing target is valid then be sure to set the override bit so that it always
|
||||
// gets executed next
|
||||
if ( aigp->ai_mode == AI_GOAL_FORM_ON_WING ) {
|
||||
sindex = ship_name_lookup( aigp->target_name );
|
||||
|
||||
if (sindex < 0)
|
||||
if (!target_ship_entry || !target_ship_entry->shipp)
|
||||
return ai_achievability::NOT_ACHIEVABLE;
|
||||
|
||||
aigp->flags.set(AI::Goal_Flags::Goal_override);
|
||||
@@ -1625,11 +1646,10 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
|
||||
// shipnum could be -1 depending on if the ship hasn't arrived or died. only look for subsystem
|
||||
// destroyed when shipnum is valid
|
||||
sindex = ship_name_lookup( aigp->target_name );
|
||||
|
||||
// can't determine the status of this goal if ship not valid
|
||||
// or we haven't found a valid subsystem index yet
|
||||
if ( (sindex == -1) || (aigp->flags[AI::Goal_Flags::Subsys_needs_fixup]) ) {
|
||||
if ( !target_ship_entry || !target_ship_entry->shipp || (aigp->flags[AI::Goal_Flags::Subsys_needs_fixup]) ) {
|
||||
status = 0;
|
||||
break;
|
||||
}
|
||||
@@ -1638,46 +1658,46 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
// as 0 so we can continue. (The subsystem name must be turned into an index into the ship's subsystems
|
||||
// for this goal to be valid).
|
||||
Assert ( aigp->ai_submode >= 0 );
|
||||
ssp = ship_get_indexed_subsys( &Ships[sindex], aigp->ai_submode );
|
||||
ssp = ship_get_indexed_subsys( target_ship_entry->shipp, aigp->ai_submode );
|
||||
if (ssp != NULL) {
|
||||
// see MWA 3/20/97 comment above - instead of checking the mission log, check the current hits
|
||||
status = (ssp->current_hits <= 0.0f) ? 1 : 0;
|
||||
} else {
|
||||
// not supposed to ever happen, but could if there is a mismatch between the table and model subsystems
|
||||
nprintf(("AI", "Couldn't find subsystem %d for ship %s\n", aigp->ai_submode, Ships[sindex].ship_name));
|
||||
nprintf(("AI", "Couldn't find subsystem %d for ship %s\n", aigp->ai_submode, target_ship_entry->shipp->ship_name));
|
||||
status = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case AI_GOAL_DISABLE_SHIP:
|
||||
case AI_GOAL_DISABLE_SHIP_TACTICAL:
|
||||
{
|
||||
// shipnum could be -1 depending on if the ship hasn't arrived or died. only look for subsystem
|
||||
// destroyed when shipnum is valid
|
||||
sindex = ship_name_lookup(aigp->target_name);
|
||||
|
||||
// can't determine the status of this goal if ship not valid
|
||||
if (sindex < 0) {
|
||||
if (!target_ship_entry || !target_ship_entry->shipp) {
|
||||
status = 0;
|
||||
} else {
|
||||
// see MWA 3/20/97 comment above - instead of checking the mission log, check the current hits
|
||||
status = (Ships[sindex].subsys_info[SUBSYSTEM_ENGINE].aggregate_current_hits <= 0.0f) ? 1 : 0;
|
||||
status = (target_ship_entry->shipp->subsys_info[SUBSYSTEM_ENGINE].aggregate_current_hits <= 0.0f) ? 1 : 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case AI_GOAL_DISARM_SHIP:
|
||||
case AI_GOAL_DISARM_SHIP_TACTICAL:
|
||||
{
|
||||
// shipnum could be -1 depending on if the ship hasn't arrived or died. only look for subsystem
|
||||
// destroyed when shipnum is valid
|
||||
sindex = ship_name_lookup(aigp->target_name);
|
||||
|
||||
// can't determine the status of this goal if ship not valid
|
||||
if (sindex < 0) {
|
||||
if (!target_ship_entry || !target_ship_entry->shipp) {
|
||||
status = 0;
|
||||
} else {
|
||||
// see MWA 3/20/97 comment above - instead of checking the mission log, check the current hits
|
||||
status = (Ships[sindex].subsys_info[SUBSYSTEM_TURRET].aggregate_current_hits <= 0.0f) ? 1 : 0;
|
||||
status = (target_ship_entry->shipp->subsys_info[SUBSYSTEM_TURRET].aggregate_current_hits <= 0.0f) ? 1 : 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1696,22 +1716,23 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
// MWA -- 4/22/98. Check for the ship actually being in the mission before
|
||||
// checking departure and destroyed. In multiplayer, since ships can respawn,
|
||||
// they get log entries for being destroyed even though they have respawned.
|
||||
sindex = ship_name_lookup( aigp->target_name );
|
||||
if ( sindex < 0 ) {
|
||||
status = mission_log_get_time( LOG_SHIP_DEPARTED, aigp->target_name, NULL, NULL);
|
||||
if ( !status ) {
|
||||
status = mission_log_get_time( LOG_SHIP_DESTROYED, aigp->target_name, NULL, NULL);
|
||||
if ( !status ) {
|
||||
status = mission_log_get_time( LOG_SELF_DESTRUCTED, aigp->target_name, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if ( status )
|
||||
return_val = ai_achievability::NOT_ACHIEVABLE;
|
||||
// Goober5000 - update this to use ship registry status with similar logic
|
||||
if (target_ship_entry && target_ship_entry->status == ShipStatus::EXITED) {
|
||||
status = 1;
|
||||
return_val = ai_achievability::NOT_ACHIEVABLE;
|
||||
} else {
|
||||
status = 0;
|
||||
}
|
||||
|
||||
// fly-to-ship can potentially be determined
|
||||
if (aigp->ai_mode == AI_GOAL_FLY_TO_SHIP && target_ship_entry && target_ship_entry->objp) {
|
||||
auto dist = vm_vec_dist(&target_ship_entry->objp->pos, &objp->pos);
|
||||
if (dist < aigp->float_data) {
|
||||
return_val = ai_achievability::SATISFIED;
|
||||
status = 1;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1749,7 +1770,7 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
}
|
||||
|
||||
default:
|
||||
Int3();
|
||||
UNREACHABLE("Unhandled AI goal %d", aigp->ai_mode);
|
||||
status = 0;
|
||||
break;
|
||||
}
|
||||
@@ -1764,12 +1785,12 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
// the if statement.
|
||||
if ( (aigp->ai_mode == AI_GOAL_CHASE_WING) || (aigp->ai_mode == AI_GOAL_GUARD_WING) )
|
||||
{
|
||||
sindex = wing_name_lookup( aigp->target_name );
|
||||
int wingnum = wing_name_lookup( aigp->target_name );
|
||||
|
||||
if (sindex < 0)
|
||||
if (wingnum < 0)
|
||||
return ai_achievability::NOT_KNOWN;
|
||||
|
||||
wing *wingp = &Wings[sindex];
|
||||
wing *wingp = &Wings[wingnum];
|
||||
|
||||
if ( wingp->flags[Ship::Wing_Flags::Gone] )
|
||||
return ai_achievability::NOT_ACHIEVABLE;
|
||||
@@ -1786,24 +1807,22 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
}
|
||||
else
|
||||
{
|
||||
auto ship_entry = ship_registry_get(aigp->target_name);
|
||||
|
||||
if (!ship_entry)
|
||||
if (!target_ship_entry)
|
||||
{
|
||||
status = SHIP_STATUS_UNKNOWN;
|
||||
}
|
||||
// goal ship is currently in mission
|
||||
else if (ship_entry->status == ShipStatus::PRESENT)
|
||||
else if (target_ship_entry->status == ShipStatus::PRESENT || target_ship_entry->status == ShipStatus::DEATH_ROLL)
|
||||
{
|
||||
status = SHIP_STATUS_ARRIVED;
|
||||
}
|
||||
// goal ship is still on the arrival list
|
||||
else if (ship_entry->status == ShipStatus::NOT_YET_PRESENT)
|
||||
else if (target_ship_entry->status == ShipStatus::NOT_YET_PRESENT)
|
||||
{
|
||||
status = SHIP_STATUS_NOT_ARRIVED;
|
||||
}
|
||||
// goal ship has left the area
|
||||
else if (ship_entry->status == ShipStatus::EXITED)
|
||||
else if (target_ship_entry->status == ShipStatus::EXITED)
|
||||
{
|
||||
status = SHIP_STATUS_GONE;
|
||||
}
|
||||
@@ -1814,16 +1833,21 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
|
||||
if (status == SHIP_STATUS_UNKNOWN)
|
||||
{
|
||||
mprintf(("Potentially incorrect behaviour in AI goal for ship %s: Ship %s could not be found among currently active, departed, or yet-to-arrive ships.\nPlease check the mission file.\n", Ships[objp->instance].ship_name, aigp->target_name));
|
||||
mprintf(("Potentially incorrect behaviour in AI goal for ship %s: Ship %s could not be found among currently active, departed, or yet-to-arrive ships.\nPlease check the mission file.\n", shipp->ship_name, aigp->target_name));
|
||||
}
|
||||
}
|
||||
|
||||
// Goober5000 - before doing anything else, check if this is a disarm goal for an arrived ship...
|
||||
if ((status == SHIP_STATUS_ARRIVED) && (aigp->ai_mode == AI_GOAL_DISARM_SHIP))
|
||||
if ((status == SHIP_STATUS_ARRIVED) && (aigp->ai_mode == AI_GOAL_DISARM_SHIP || aigp->ai_mode == AI_GOAL_DISARM_SHIP_TACTICAL))
|
||||
{
|
||||
// if the ship has no turrets, we can't disarm it!
|
||||
if (Ships[ship_name_lookup(aigp->target_name)].subsys_info[SUBSYSTEM_TURRET].type_count == 0)
|
||||
return ai_achievability::NOT_ACHIEVABLE;
|
||||
if (target_ship_entry && target_ship_entry->shipp) {
|
||||
// if the ship has no turrets, we can't disarm it!
|
||||
if (target_ship_entry->shipp->subsys_info[SUBSYSTEM_TURRET].type_count == 0)
|
||||
return ai_achievability::NOT_ACHIEVABLE;
|
||||
} else {
|
||||
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
|
||||
return ai_achievability::NOT_ACHIEVABLE; // force this goal to be invalid
|
||||
}
|
||||
}
|
||||
|
||||
// if the goal is an ignore/disable/disarm goal, then
|
||||
@@ -1845,37 +1869,36 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
// this goal will get removed.
|
||||
if ( (aigp->ai_mode == AI_GOAL_DOCK) && (status == SHIP_STATUS_ARRIVED) ) {
|
||||
if (!(aigp->flags[AI::Goal_Flags::Docker_index_valid])) {
|
||||
modelnum = Ship_info[Ships[objp->instance].ship_info_index].model_num;
|
||||
int modelnum = Ship_info[shipp->ship_info_index].model_num;
|
||||
Assert( modelnum >= 0 );
|
||||
index = model_find_dock_name_index(modelnum, aigp->docker.name);
|
||||
aigp->docker.index = index;
|
||||
aigp->docker.index = model_find_dock_name_index(modelnum, aigp->docker.name);
|
||||
aigp->flags.set(AI::Goal_Flags::Docker_index_valid);
|
||||
}
|
||||
|
||||
if (!(aigp->flags[AI::Goal_Flags::Dockee_index_valid])) {
|
||||
sindex = ship_name_lookup(aigp->target_name);
|
||||
if ( sindex != -1 ) {
|
||||
modelnum = Ship_info[Ships[sindex].ship_info_index].model_num;
|
||||
index = model_find_dock_name_index(modelnum, aigp->dockee.name);
|
||||
aigp->dockee.index = index;
|
||||
if (target_ship_entry && target_ship_entry->shipp) {
|
||||
int modelnum = Ship_info[target_ship_entry->shipp->ship_info_index].model_num;
|
||||
aigp->dockee.index = model_find_dock_name_index(modelnum, aigp->dockee.name);
|
||||
aigp->flags.set(AI::Goal_Flags::Dockee_index_valid);
|
||||
} else
|
||||
aigp->dockee.index = -1; // this will force code into if statement below making goal not achievable.
|
||||
}
|
||||
|
||||
if ( (aigp->dockee.index == -1) || (aigp->docker.index == -1) ) {
|
||||
Int3(); // for now, allender wants to know about these things!!!!
|
||||
Warning(LOCATION, "Cannot determine docking information for %s!", shipp->ship_name); // for now, allender wants to know about these things!!!!
|
||||
return ai_achievability::NOT_ACHIEVABLE;
|
||||
}
|
||||
|
||||
// if ship is disabled, don't know if it can dock or not
|
||||
if ( Ships[objp->instance].flags[Ship::Ship_Flags::Disabled] )
|
||||
if ( shipp->flags[Ship::Ship_Flags::Disabled] )
|
||||
return ai_achievability::NOT_KNOWN;
|
||||
|
||||
// we must also determine if we're prevented from docking for any reason
|
||||
sindex = ship_name_lookup(aigp->target_name);
|
||||
Assert( sindex >= 0 );
|
||||
object *goal_objp = &Objects[Ships[sindex].objnum];
|
||||
if (!target_ship_entry || !target_ship_entry->shipp) {
|
||||
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
|
||||
return ai_achievability::NOT_ACHIEVABLE; // force this goal to be invalid
|
||||
}
|
||||
auto goal_objp = target_ship_entry->objp;
|
||||
|
||||
// if the ship that I am supposed to dock with is docked with something else, then I need to put my goal on hold
|
||||
// [MK, 4/23/98: With Mark, we believe this fixes the problem of Comet refusing to warp out after docking with Omega.
|
||||
@@ -1924,9 +1947,14 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
// might happen too, so err on the safe side. (Yay for emergent paragraph justification!)
|
||||
if ((aip->mode == AIM_DOCK) && (aip->submode >= AIS_UNDOCK_0))
|
||||
{
|
||||
// only put it on hold if it's someone other than the guy we're undocking from right now!!
|
||||
if (aip->goal_objnum != Ships[ship_name_lookup(aigp->target_name)].objnum)
|
||||
return ai_achievability::NOT_KNOWN;
|
||||
if ( target_ship_entry && target_ship_entry->shipp ) {
|
||||
// only put it on hold if it's someone other than the guy we're undocking from right now!!
|
||||
if (aip->goal_objnum != target_ship_entry->shipp->objnum)
|
||||
return ai_achievability::NOT_KNOWN;
|
||||
} else {
|
||||
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
|
||||
return ai_achievability::NOT_ACHIEVABLE; // force this goal to be invalid
|
||||
}
|
||||
}
|
||||
|
||||
} else if ( (aigp->ai_mode == AI_GOAL_DESTROY_SUBSYSTEM) && (status == SHIP_STATUS_ARRIVED) ) {
|
||||
@@ -1934,23 +1962,21 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
// have fixed up the subsystem name (of the subsystem to destroy) into an index into
|
||||
// the ship's subsystem list
|
||||
if ( aigp->flags[AI::Goal_Flags::Subsys_needs_fixup] ) {
|
||||
sindex = ship_name_lookup( aigp->target_name );
|
||||
|
||||
if ( sindex != -1 ) {
|
||||
aigp->ai_submode = ship_find_subsys( &Ships[sindex], aigp->docker.name );
|
||||
if ( target_ship_entry && target_ship_entry->shipp ) {
|
||||
aigp->ai_submode = ship_find_subsys( target_ship_entry->shipp, aigp->docker.name );
|
||||
aigp->flags.remove(AI::Goal_Flags::Subsys_needs_fixup);
|
||||
} else {
|
||||
Int3();
|
||||
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
|
||||
return ai_achievability::NOT_ACHIEVABLE; // force this goal to be invalid
|
||||
}
|
||||
}
|
||||
} else if ( ((aigp->ai_mode == AI_GOAL_IGNORE) || (aigp->ai_mode == AI_GOAL_IGNORE_NEW)) && (status == SHIP_STATUS_ARRIVED) ) {
|
||||
object *ignored;
|
||||
|
||||
// for ignoring a ship, call the ai_ignore object function, then declare the goal satisfied
|
||||
sindex = ship_name_lookup( aigp->target_name );
|
||||
Assert( sindex != -1 ); // should be true because of above status
|
||||
ignored = &Objects[Ships[sindex].objnum];
|
||||
if (!target_ship_entry || !target_ship_entry->shipp) {
|
||||
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
|
||||
return ai_achievability::NOT_ACHIEVABLE; // force this goal to be invalid
|
||||
}
|
||||
auto ignored = target_ship_entry->objp;
|
||||
|
||||
ai_ignore_object(objp, ignored, (aigp->ai_mode == AI_GOAL_IGNORE_NEW));
|
||||
|
||||
@@ -1966,7 +1992,9 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
case AI_GOAL_GUARD:
|
||||
case AI_GOAL_GUARD_WING:
|
||||
case AI_GOAL_DISABLE_SHIP:
|
||||
case AI_GOAL_DISABLE_SHIP_TACTICAL:
|
||||
case AI_GOAL_DISARM_SHIP:
|
||||
case AI_GOAL_DISARM_SHIP_TACTICAL:
|
||||
case AI_GOAL_DESTROY_SUBSYSTEM:
|
||||
case AI_GOAL_IGNORE:
|
||||
case AI_GOAL_IGNORE_NEW:
|
||||
@@ -1983,7 +2011,7 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
else if ( status == SHIP_STATUS_UNKNOWN )
|
||||
return ai_achievability::NOT_KNOWN;
|
||||
|
||||
Int3(); // get allender -- bad logic
|
||||
UNREACHABLE("Invalid status variable %d for ship %s; get Allender or a SCP member", status, shipp->ship_name); // get allender -- bad logic
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1995,31 +2023,29 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
// short circuit a couple of cases. Ship not arrived shouldn't happen. Ship gone means
|
||||
// we mark the goal as not achievable.
|
||||
if ( status == SHIP_STATUS_NOT_ARRIVED ) {
|
||||
Int3(); // get Allender. this shouldn't happen!!!
|
||||
UNREACHABLE("Ship %s cannot rearm a target %s that hasn't arrived; get Allender or a SCP member", shipp->ship_name, aigp->target_name); // get Allender. this shouldn't happen!!!
|
||||
return ai_achievability::NOT_ACHIEVABLE;
|
||||
}
|
||||
|
||||
if ( status == SHIP_STATUS_GONE )
|
||||
return ai_achievability::NOT_ACHIEVABLE;
|
||||
|
||||
sindex = ship_name_lookup( aigp->target_name );
|
||||
|
||||
if ( sindex < 0 ) {
|
||||
Int3();
|
||||
if ( !target_ship_entry || !target_ship_entry->shipp ) {
|
||||
UNREACHABLE("Target name %s is not an arrived ship!", aigp->target_name);
|
||||
return ai_achievability::NOT_ACHIEVABLE;
|
||||
}
|
||||
|
||||
// if desitnation currently being repaired, then goal is stil active
|
||||
if ( Ai_info[Ships[sindex].ai_index].ai_flags[AI::AI_Flags::Being_repaired] )
|
||||
// if destination currently being repaired, then goal is still active
|
||||
if ( Ai_info[target_ship_entry->shipp->ai_index].ai_flags[AI::AI_Flags::Being_repaired] )
|
||||
return ai_achievability::ACHIEVABLE;
|
||||
|
||||
// if the destination ship is dying or departing (but not completed yet), the mark goal as
|
||||
// not achievable.
|
||||
if ( Ships[sindex].is_dying_or_departing())
|
||||
if ( target_ship_entry->shipp->is_dying_or_departing())
|
||||
return ai_achievability::NOT_ACHIEVABLE;
|
||||
|
||||
// if the destination object is no longer awaiting repair, then remove the item
|
||||
if ( !(Ai_info[Ships[sindex].ai_index].ai_flags[AI::AI_Flags::Awaiting_repair]) )
|
||||
if ( !(Ai_info[target_ship_entry->shipp->ai_index].ai_flags[AI::AI_Flags::Awaiting_repair]) )
|
||||
return ai_achievability::NOT_ACHIEVABLE;
|
||||
|
||||
// not repairing anything means that he can do this goal!!!
|
||||
@@ -2034,14 +2060,14 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
// if he is repairing something, he can satisfy his repair goal (his goal_objnum)
|
||||
// return GOAL_NOT_KNOWN which is kind of a hack which puts the goal on hold until it can be
|
||||
// satisfied.
|
||||
if ( aip->goal_objnum != Ships[sindex].objnum )
|
||||
if ( aip->goal_objnum != target_ship_entry->shipp->objnum )
|
||||
return ai_achievability::NOT_KNOWN;
|
||||
|
||||
return ai_achievability::ACHIEVABLE;
|
||||
}
|
||||
|
||||
default:
|
||||
Int3(); // invalid case in switch:
|
||||
UNREACHABLE("Unhandled AI goal %d", aigp->ai_mode); // invalid case in switch:
|
||||
}
|
||||
|
||||
return ai_achievability::NOT_KNOWN;
|
||||
@@ -2315,12 +2341,6 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
|
||||
break;
|
||||
}
|
||||
|
||||
case AI_GOAL_FLY_TO_SHIP:
|
||||
shipnum = ship_name_lookup( current_goal->target_name );
|
||||
Assert (shipnum != -1 ); // shouldn't get here if this is false!!!!
|
||||
ai_start_fly_to_ship(objp, shipnum);
|
||||
break;
|
||||
|
||||
case AI_GOAL_DOCK: {
|
||||
shipnum = ship_name_lookup( current_goal->target_name );
|
||||
Assert (shipnum != -1 ); // shouldn't get here if this is false!!!!
|
||||
@@ -2395,22 +2415,27 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
|
||||
break;
|
||||
|
||||
|
||||
// when destroying a subsystem, we can destroy a specific instance of a subsystem
|
||||
// or all instances of a type of subsystem (i.e. a specific engine or all engines).
|
||||
// the ai_submode value is > 0 for a specific instance of subsystem and < 0 for all
|
||||
// instances of a specific type
|
||||
// when destroying a subsystem, we can destroy a specific instance of a subsystem
|
||||
// or all instances of a type of subsystem (i.e. a specific engine or all engines).
|
||||
// the ai_submode value is > 0 for a specific instance of subsystem and < 0 for all
|
||||
// instances of a specific type
|
||||
case AI_GOAL_DESTROY_SUBSYSTEM:
|
||||
case AI_GOAL_DISABLE_SHIP:
|
||||
case AI_GOAL_DISARM_SHIP: {
|
||||
case AI_GOAL_DISABLE_SHIP_TACTICAL:
|
||||
case AI_GOAL_DISARM_SHIP:
|
||||
case AI_GOAL_DISARM_SHIP_TACTICAL: {
|
||||
shipnum = ship_name_lookup( current_goal->target_name );
|
||||
Assert( shipnum >= 0 );
|
||||
other_obj = &Objects[Ships[shipnum].objnum];
|
||||
ai_attack_object( objp, other_obj);
|
||||
ai_set_attack_subsystem( objp, current_goal->ai_submode ); // submode stored the subsystem type
|
||||
if (current_goal->ai_mode != AI_GOAL_DESTROY_SUBSYSTEM) {
|
||||
|
||||
// don't protect-ship for tactical goals
|
||||
if (current_goal->ai_mode != AI_GOAL_DESTROY_SUBSYSTEM && current_goal->ai_mode != AI_GOAL_DISABLE_SHIP_TACTICAL && current_goal->ai_mode != AI_GOAL_DISARM_SHIP_TACTICAL) {
|
||||
if (aip->target_objnum != -1) {
|
||||
int class_type = Ship_info[Ships[shipnum].ship_info_index].class_type;
|
||||
// Only protect if _not_ a capital ship. We don't want the Lucifer accidentally getting protected.
|
||||
if (Ship_types[Ship_info[Ships[shipnum].ship_info_index].class_type].flags[Ship::Type_Info_Flags::AI_protected_on_cripple])
|
||||
if (class_type >= 0 && Ship_types[class_type].flags[Ship::Type_Info_Flags::AI_protected_on_cripple])
|
||||
Objects[aip->target_objnum].flags.set(Object::Object_Flags::Protected);
|
||||
}
|
||||
} else // Just in case this ship had been protected, unprotect it.
|
||||
@@ -2488,14 +2513,17 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
|
||||
|
||||
// labels for support ship commands
|
||||
|
||||
case AI_GOAL_STAY_NEAR_SHIP: {
|
||||
case AI_GOAL_STAY_NEAR_SHIP:
|
||||
case AI_GOAL_FLY_TO_SHIP:
|
||||
{
|
||||
shipnum = ship_name_lookup( current_goal->target_name );
|
||||
Assert( shipnum >= 0 );
|
||||
other_obj = &Objects[Ships[shipnum].objnum];
|
||||
float dist = current_goal->float_data; // How far away to stay from ship. Should be set in SEXP?
|
||||
ai_do_stay_near(objp, other_obj, dist);
|
||||
int additional_data = current_goal->int_data; // Whether to target a particular point as if escorting
|
||||
ai_do_stay_near(objp, other_obj, dist, additional_data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
case AI_GOAL_KEEP_SAFE_DISTANCE:
|
||||
// todo MK: hook to keep support ship at a safe distance
|
||||
@@ -2543,7 +2571,9 @@ void ai_update_goal_references(ai_goal *goals, sexp_ref_type type, const char *o
|
||||
case AI_GOAL_DESTROY_SUBSYSTEM:
|
||||
case AI_GOAL_GUARD:
|
||||
case AI_GOAL_DISABLE_SHIP:
|
||||
case AI_GOAL_DISABLE_SHIP_TACTICAL:
|
||||
case AI_GOAL_DISARM_SHIP:
|
||||
case AI_GOAL_DISARM_SHIP_TACTICAL:
|
||||
case AI_GOAL_IGNORE:
|
||||
case AI_GOAL_IGNORE_NEW:
|
||||
case AI_GOAL_EVADE_SHIP:
|
||||
@@ -2617,7 +2647,9 @@ bool query_referenced_in_ai_goals(ai_goal *goals, sexp_ref_type type, const char
|
||||
case AI_GOAL_DESTROY_SUBSYSTEM:
|
||||
case AI_GOAL_GUARD:
|
||||
case AI_GOAL_DISABLE_SHIP:
|
||||
case AI_GOAL_DISABLE_SHIP_TACTICAL:
|
||||
case AI_GOAL_DISARM_SHIP:
|
||||
case AI_GOAL_DISARM_SHIP_TACTICAL:
|
||||
case AI_GOAL_IGNORE:
|
||||
case AI_GOAL_IGNORE_NEW:
|
||||
case AI_GOAL_EVADE_SHIP:
|
||||
|
||||
+5
-3
@@ -73,15 +73,17 @@ struct ai_info;
|
||||
#define AI_GOAL_FLY_TO_SHIP (1<<23) // 0x00800000
|
||||
#define AI_GOAL_IGNORE_NEW (1<<24) // 0x01000000
|
||||
#define AI_GOAL_CHASE_SHIP_CLASS (1<<25) // 0x02000000
|
||||
#define AI_GOAL_PLAY_DEAD_PERSISTENT (1<<26) // 0x03000000
|
||||
#define AI_GOAL_LUA (1<<27) // 0x04000000
|
||||
#define AI_GOAL_PLAY_DEAD_PERSISTENT (1<<26) // 0x04000000
|
||||
#define AI_GOAL_LUA (1<<27) // 0x08000000
|
||||
#define AI_GOAL_DISARM_SHIP_TACTICAL (1<<28) // 0x10000000
|
||||
#define AI_GOAL_DISABLE_SHIP_TACTICAL (1<<29) // 0x20000000
|
||||
|
||||
// now the masks for ship types
|
||||
|
||||
// Goober5000: added AI_GOAL_STAY_NEAR_SHIP and AI_GOAL_KEEP_SAFE_DISTANCE as valid for fighters
|
||||
//WMC - Don't need these anymore. Whee!
|
||||
/*
|
||||
#define AI_GOAL_ACCEPT_FIGHTER ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_CHASE | AI_GOAL_WAYPOINTS | AI_GOAL_WAYPOINTS_ONCE | AI_GOAL_WARP | AI_GOAL_DESTROY_SUBSYSTEM | AI_GOAL_CHASE_WING | AI_GOAL_GUARD | AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP | AI_GOAL_CHASE_ANY | AI_GOAL_IGNORE | AI_GOAL_IGNORE_NEW | AI_GOAL_GUARD_WING | AI_GOAL_EVADE_SHIP | AI_GOAL_STAY_STILL | AI_GOAL_PLAY_DEAD | AI_GOAL_PLAY_DEAD_PERSISTENT | AI_GOAL_STAY_NEAR_SHIP | AI_GOAL_KEEP_SAFE_DISTANCE )
|
||||
#define AI_GOAL_ACCEPT_FIGHTER ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_CHASE | AI_GOAL_WAYPOINTS | AI_GOAL_WAYPOINTS_ONCE | AI_GOAL_WARP | AI_GOAL_DESTROY_SUBSYSTEM | AI_GOAL_CHASE_WING | AI_GOAL_GUARD | AI_GOAL_DISABLE_SHIP | AI_GOAL_DISABLE_SHIP_TACTICAL | AI_GOAL_DISARM_SHIP | AI_GOAL_DISARM_SHIP_TACTICAL | AI_GOAL_CHASE_ANY | AI_GOAL_IGNORE | AI_GOAL_IGNORE_NEW | AI_GOAL_GUARD_WING | AI_GOAL_EVADE_SHIP | AI_GOAL_STAY_STILL | AI_GOAL_PLAY_DEAD | AI_GOAL_PLAY_DEAD_PERSISTENT | AI_GOAL_STAY_NEAR_SHIP | AI_GOAL_KEEP_SAFE_DISTANCE )
|
||||
#define AI_GOAL_ACCEPT_BOMBER ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_FIGHTER | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_STEALTH ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_FIGHTER | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_TRANSPORT ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_CHASE | AI_GOAL_CHASE_WING | AI_GOAL_DOCK | AI_GOAL_WAYPOINTS | AI_GOAL_WAYPOINTS_ONCE | AI_GOAL_WARP | AI_GOAL_UNDOCK | AI_GOAL_STAY_STILL | AI_GOAL_PLAY_DEAD | AI_GOAL_PLAY_DEAD_PERSISTENT | AI_GOAL_STAY_NEAR_SHIP )
|
||||
|
||||
+162
-5
@@ -18,9 +18,9 @@ void ai_lua_add_mode(int sexp_op, const ai_mode_lua& mode) {
|
||||
}
|
||||
|
||||
bool ai_lua_add_order(int sexp_op, player_order_lua order) {
|
||||
Player_orders.emplace_back(vm_strdup(order.parseText.c_str()), vm_strdup(order.displayText.c_str()), -1, sexp_op);
|
||||
Player_orders.emplace_back(order.parseText, order.displayText, -1, sexp_op);
|
||||
Player_orders.back().localize();
|
||||
|
||||
|
||||
Lua_player_orders.emplace(sexp_op, std::move(order));
|
||||
|
||||
return true;
|
||||
@@ -48,6 +48,134 @@ const player_order_lua* ai_lua_find_player_order(int sexp_op) {
|
||||
return &aiLuaOrder->second;
|
||||
}
|
||||
|
||||
int ai_lua_get_num_general_orders() {
|
||||
int count = 0;
|
||||
|
||||
for (const auto& order : Lua_player_orders) {
|
||||
if (order.second.generalOrder) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
SCP_vector<SCP_string> ai_lua_get_general_order_categories(bool enabled_only)
|
||||
{
|
||||
SCP_vector<SCP_string> list;
|
||||
|
||||
for (const auto& order : Lua_player_orders) {
|
||||
const SCP_string &cat = order.second.category;
|
||||
|
||||
// If it's not a general order then move on
|
||||
if (!order.second.generalOrder) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the order is not enabled then move on
|
||||
if (enabled_only && !order.second.cur_enabled) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Assertion((cat.length() > 0), "Lua general orders category name must be longer than 0 characters!");
|
||||
|
||||
for (size_t i = 0; i <= list.size(); i++) {
|
||||
|
||||
// reached the end of the list, so add it
|
||||
if (i == list.size()) {
|
||||
list.push_back(cat);
|
||||
break;
|
||||
}
|
||||
|
||||
// if it's already in the list then don't add it
|
||||
if (cat == list[i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
SCP_vector<SCP_string> ai_lua_get_general_orders(bool onlyEnabled, bool onlyValid, const SCP_string& category)
|
||||
{
|
||||
SCP_vector<SCP_string> list;
|
||||
|
||||
for (auto order : Lua_player_orders) {
|
||||
if (order.second.generalOrder) {
|
||||
bool add = false;
|
||||
|
||||
// Only enabled orders
|
||||
if (onlyEnabled && order.second.cur_enabled) {
|
||||
add = true;
|
||||
|
||||
// Only valid orders
|
||||
} else if (onlyValid && order.second.cur_valid) {
|
||||
add = true;
|
||||
|
||||
// Only orders that match the category requested
|
||||
} else if ((!category.empty()) && (order.second.category == category)) {
|
||||
add = true;
|
||||
|
||||
// All general orders
|
||||
} else {
|
||||
add = true;
|
||||
}
|
||||
|
||||
if (add) {
|
||||
list.push_back(order.second.parseText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
int ai_lua_find_general_order_id(const SCP_string& name) {
|
||||
for (const auto& order : Lua_player_orders) {
|
||||
if (order.second.parseText == name) {
|
||||
return order.first;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void ai_lua_enable_general_order(int sexp_op, bool enable) {
|
||||
auto aiLuaOrder = Lua_player_orders.find(sexp_op);
|
||||
|
||||
if (aiLuaOrder == Lua_player_orders.end())
|
||||
return;
|
||||
else
|
||||
aiLuaOrder->second.cur_enabled = enable;
|
||||
}
|
||||
|
||||
void ai_lua_validate_general_order(int sexp_op, bool validity)
|
||||
{
|
||||
auto aiLuaOrder = Lua_player_orders.find(sexp_op);
|
||||
|
||||
if (aiLuaOrder == Lua_player_orders.end())
|
||||
return;
|
||||
else
|
||||
aiLuaOrder->second.cur_valid = validity;
|
||||
}
|
||||
|
||||
void ai_lua_reset_general_orders() {
|
||||
for (auto order : Lua_player_orders) {
|
||||
ai_lua_enable_general_order(order.first, false);
|
||||
ai_lua_validate_general_order(order.first, false);
|
||||
}
|
||||
}
|
||||
|
||||
bool ai_lua_is_general_order(int sexp_op) {
|
||||
auto aiLuaOrder = Lua_player_orders.find(sexp_op);
|
||||
|
||||
if (aiLuaOrder == Lua_player_orders.end())
|
||||
return false;
|
||||
|
||||
return aiLuaOrder->second.generalOrder;
|
||||
}
|
||||
|
||||
void run_ai_lua_action(const luacpp::LuaFunction& action, const ai_mode_lua& lua_ai, ai_info* aip) {
|
||||
if (!action.isValid()) {
|
||||
Error(LOCATION,
|
||||
@@ -56,7 +184,11 @@ void run_ai_lua_action(const luacpp::LuaFunction& action, const ai_mode_lua& lua
|
||||
}
|
||||
|
||||
luacpp::LuaValueList luaParameters;
|
||||
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_AI_Helper.Set(object_h(&Objects[Ships[aip->shipnum].objnum]))));
|
||||
if (aip->shipnum >= 0){
|
||||
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_AI_Helper.Set(object_h(&Objects[Ships[aip->shipnum].objnum]))));
|
||||
} else {
|
||||
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_AI_Helper.Set(object_h())));
|
||||
}
|
||||
if (lua_ai.needsTarget) {
|
||||
luaParameters.push_back(luacpp::LuaValue::createValue(action.getLuaState(), scripting::api::l_OSWPT.Set(aip->lua_ai_target.target)));
|
||||
}
|
||||
@@ -67,8 +199,13 @@ void run_ai_lua_action(const luacpp::LuaFunction& action, const ai_mode_lua& lua
|
||||
auto retVals = action.call(Script_system.GetLuaSession(), luaParameters);
|
||||
|
||||
if (!retVals.empty() && retVals[0].getValueType() == luacpp::ValueType::BOOLEAN) {
|
||||
if (retVals[0].getValue<bool>())
|
||||
ai_mission_goal_complete(aip);
|
||||
if (retVals[0].getValue<bool>()) {
|
||||
|
||||
// If we don't have a ship then it's a general order and we have nothing else to do
|
||||
if (aip->shipnum >= 0) {
|
||||
ai_mission_goal_complete(aip);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,6 +240,26 @@ void ai_lua_start(ai_goal* aigp, object* objp){
|
||||
run_ai_lua_action(action, lua_ai, aip);
|
||||
}
|
||||
|
||||
// For sending general orders that don't run on a ship.
|
||||
// Essentially just runs arbitrary lua script when the command is called
|
||||
void ai_lua_start_general(int lua_sexp_id, int target_objnum)
|
||||
{
|
||||
//Create a dummy aip to pass the target data
|
||||
ai_info aip;
|
||||
aip.shipnum = -1;
|
||||
|
||||
if (target_objnum >= 0) {
|
||||
aip.lua_ai_target = {object_ship_wing_point_team(&Ships[Objects[target_objnum].instance]), {}};
|
||||
}
|
||||
|
||||
const auto& lua_ai = ai_lua_find_mode(lua_sexp_id);
|
||||
|
||||
const auto& lua_ai_sexp = lua_ai->sexp;
|
||||
const auto& action = lua_ai_sexp.getActionEnter();
|
||||
|
||||
run_ai_lua_action(action, *lua_ai, &aip);
|
||||
}
|
||||
|
||||
bool ai_lua_is_valid_target_intrinsic(int sexp_op, int target_objnum, ship* self) {
|
||||
ship* target = &Ships[Objects[target_objnum].instance];
|
||||
|
||||
|
||||
@@ -19,6 +19,10 @@ struct player_order_lua {
|
||||
int ai_message = MESSAGE_YESSIR;
|
||||
SCP_string parseText = "";
|
||||
SCP_string displayText = "";
|
||||
bool generalOrder = false;
|
||||
SCP_string category = "";
|
||||
bool cur_enabled = false;
|
||||
bool cur_valid = false;
|
||||
enum class target_restrictions : int { TARGET_ALLIES, TARGET_ALL, TARGET_OWN, TARGET_ENEMIES, TARGET_SAME_WING, TARGET_PLAYER_WING, TARGET_ALL_CAPS, TARGET_ALLIED_CAPS, TARGET_ENEMY_CAPS, TARGET_NOT_SELF } targetRestrictions = target_restrictions::TARGET_ALL;
|
||||
enum class ship_restrictions : int { ANY, WING, IN_PLAYER_WING, PLAYER_WING } shipRestrictions = ship_restrictions::ANY;
|
||||
};
|
||||
@@ -29,8 +33,17 @@ bool ai_lua_add_order(int sexp_op, player_order_lua order);
|
||||
bool ai_lua_has_mode(int sexp_op);
|
||||
const ai_mode_lua* ai_lua_find_mode(int sexp_op);
|
||||
const player_order_lua* ai_lua_find_player_order(int sexp_op);
|
||||
SCP_vector<SCP_string> ai_lua_get_general_order_categories(bool enabled_only = true);
|
||||
int ai_lua_get_num_general_orders();
|
||||
SCP_vector<SCP_string> ai_lua_get_general_orders(bool onlyEnabled = false, bool onlyValid = false, const SCP_string& category = "");
|
||||
int ai_lua_find_general_order_id(const SCP_string& name);
|
||||
void ai_lua_enable_general_order(int sexp_op, bool enable);
|
||||
void ai_lua_validate_general_order(int sexp_op, bool validity);
|
||||
void ai_lua_reset_general_orders();
|
||||
bool ai_lua_is_general_order(int sexp_op);
|
||||
void ai_lua(ai_info* aip);
|
||||
void ai_lua_start(ai_goal* aigp, object* objp);
|
||||
void ai_lua_start_general(int lua_sexp_id, int target_objnum);
|
||||
bool ai_lua_is_valid_target(int sexp_op, int target_objnum, ship* self, size_t order);
|
||||
bool ai_lua_is_valid_ship(int sexp_op, bool isWing, ship* self);
|
||||
ai_achievability ai_lua_is_achievable(const ai_goal* aigp, int objnum);
|
||||
@@ -1104,7 +1104,7 @@ int find_turret_enemy(ship_subsys *turret_subsys, int objnum, vec3d *tpos, vec3d
|
||||
ai_info *aip = &Ai_info[Ships[Objects[objnum].instance].ai_index];
|
||||
sip = &Ship_info[Ships[Objects[objnum].instance].ship_info_index];
|
||||
|
||||
if ((Ship_types[sip->class_type].flags[Ship::Type_Info_Flags::Turret_tgt_ship_tgt]) && (aip->target_objnum != -1)) {
|
||||
if ((sip->class_type >= 0) && (Ship_types[sip->class_type].flags[Ship::Type_Info_Flags::Turret_tgt_ship_tgt]) && (aip->target_objnum != -1)) {
|
||||
int target_objnum = aip->target_objnum;
|
||||
|
||||
if (Objects[target_objnum].signature == aip->target_signature) {
|
||||
|
||||
@@ -670,7 +670,7 @@ void anim_read_header(anim *ptr, CFILE *fp)
|
||||
* @param file_mapped Whether to use memory-mapped file or not.
|
||||
*
|
||||
* @details Memory-mapped files will page in the animation from disk as it is needed, but performance is not as good.
|
||||
* @return Pointer to anim that is loaded if sucess, NULL if failure.
|
||||
* @return Pointer to anim that is loaded if success, NULL if failure.
|
||||
*/
|
||||
anim *anim_load(const char *real_filename, int cf_dir_type, int file_mapped)
|
||||
{
|
||||
|
||||
@@ -1030,7 +1030,7 @@ bool asteroid_is_within_view(vec3d *pos, float range, bool range_override)
|
||||
float dot = vm_vec_dot(&Eye_matrix.vec.fvec, &vec_to_asteroid);
|
||||
|
||||
// if asteroid is within view or far enough away then wrap
|
||||
if (dot > cos(Proj_fov)) {
|
||||
if (dot > cos(g3_get_hfov(Proj_fov))) {
|
||||
if (range_override) {
|
||||
return true;
|
||||
} else {
|
||||
|
||||
@@ -1023,7 +1023,7 @@ void nav_warp(bool prewarp=false)
|
||||
|
||||
// retime collision pairs
|
||||
if (Objects[Ships[i].objnum].flags[Object::Object_Flags::Collides])
|
||||
obj_collide_retime_cached_pairs(&Objects[Ships[i].objnum]);
|
||||
obj_collide_obj_cache_stale(&Objects[Ships[i].objnum]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -598,7 +598,7 @@ int bm_create_3d(int bpp, int w, int h, int d, void* data) {
|
||||
|
||||
// make sure that we have valid data
|
||||
if (data == nullptr) {
|
||||
UNREACHABLE("No valid data recieved for 3D Bitmap creation!");
|
||||
UNREACHABLE("No valid data received for 3D Bitmap creation!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -2602,7 +2602,7 @@ void *bm_malloc(int n, size_t size) {
|
||||
void bm_page_in_aabitmap(int handle, int nframes) {
|
||||
int i;
|
||||
|
||||
if (handle == -1)
|
||||
if (handle < 0)
|
||||
return;
|
||||
|
||||
Assert(bm_get_entry(handle)->handle == handle);
|
||||
|
||||
+53
-21
@@ -14,8 +14,8 @@
|
||||
#include "ship/ship.h" //compute_slew_matrix
|
||||
|
||||
//*************************IMPORTANT GLOBALS*************************
|
||||
float VIEWER_ZOOM_DEFAULT = 0.75f; // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
|
||||
float COCKPIT_ZOOM_DEFAULT = 0.75f;
|
||||
fov_t VIEWER_ZOOM_DEFAULT = 0.75f; // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
|
||||
fov_t COCKPIT_ZOOM_DEFAULT = 0.75f;
|
||||
float Sexp_fov = 0.0f;
|
||||
warp_camera Warp_camera;
|
||||
|
||||
@@ -27,6 +27,33 @@ SCP_vector<camera*> Cameras;
|
||||
camid Current_camera;
|
||||
camid Main_camera;
|
||||
|
||||
asymmetric_fov operator* (const asymmetric_fov& left, const float& right) {
|
||||
return asymmetric_fov{ left.left * right, left.right * right, left.up * right, left.down * right };
|
||||
}
|
||||
asymmetric_fov operator+ (const asymmetric_fov& left, const float& right) {
|
||||
float ar = (left.up - left.down) / (left.right - left.left);
|
||||
return asymmetric_fov{ left.left - right * 0.5f, left.right + right * 0.5f, left.up + right * 0.5f * ar, left.down - right * 0.5f * ar };
|
||||
}
|
||||
asymmetric_fov operator- (const asymmetric_fov& left, const float& right) {
|
||||
float ar = (left.up - left.down) / (left.right - left.left);
|
||||
return asymmetric_fov{ left.left + right * 0.5f, left.right - right * 0.5f, left.up - right * 0.5f * ar, left.down + right * 0.5f * ar };
|
||||
}
|
||||
|
||||
#define APPLY_TO_FOV_T(op, name) \
|
||||
struct apply_##name##_to_fov { \
|
||||
float r; \
|
||||
template<typename T> \
|
||||
fov_t operator()(const T& l) { \
|
||||
return fov_t(l op r); \
|
||||
} \
|
||||
}; \
|
||||
fov_t operator op (const fov_t& zoom, const float& scale) { \
|
||||
return mpark::visit(apply_##name##_to_fov{scale}, zoom); \
|
||||
}
|
||||
APPLY_TO_FOV_T(*, mul)
|
||||
APPLY_TO_FOV_T(+, add)
|
||||
APPLY_TO_FOV_T(-, sub)
|
||||
|
||||
static SCP_string fov_display(float val)
|
||||
{
|
||||
auto degrees = fl_degrees(val);
|
||||
@@ -34,15 +61,20 @@ static SCP_string fov_display(float val)
|
||||
sprintf(out, u8"%.1f\u00B0", degrees);
|
||||
return out;
|
||||
}
|
||||
auto FovOption = options::OptionBuilder<float>("Graphics.FOV", "Field Of View", "The vertical field of view.")
|
||||
.category("Graphics")
|
||||
.range(0.436332f, 1.5708f)
|
||||
.bind_to(&VIEWER_ZOOM_DEFAULT)
|
||||
.display(fov_display)
|
||||
.default_val(0.75f)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.importance(60)
|
||||
.finish();
|
||||
auto FovOption = options::OptionBuilder<float>("Graphics.FOV",
|
||||
std::pair<const char*, int>{"Field Of View", 1703},
|
||||
std::pair<const char*, int>{"The vertical field of view", 1704})
|
||||
.category("Graphics")
|
||||
.range(0.436332f, 1.5708f)
|
||||
.change_listener([](const float& val, bool) {
|
||||
VIEWER_ZOOM_DEFAULT = val;
|
||||
return true;
|
||||
})
|
||||
.display(fov_display)
|
||||
.default_val(0.75f)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.importance(60)
|
||||
.finish();
|
||||
|
||||
//*************************CLASS: camera*************************
|
||||
//This is where the camera class begins! :D
|
||||
@@ -85,7 +117,7 @@ void camera::reset()
|
||||
func_custom_orientation = NULL;
|
||||
|
||||
fov.clear();
|
||||
fov.set(VIEWER_ZOOM_DEFAULT);
|
||||
fov.set(g3_get_hfov(VIEWER_ZOOM_DEFAULT));
|
||||
|
||||
pos_x.clear();
|
||||
pos_y.clear();
|
||||
@@ -104,7 +136,7 @@ void camera::set_name(const char *in_name)
|
||||
strncpy(name, in_name, NAME_LENGTH-1);
|
||||
}
|
||||
|
||||
void camera::set_fov(float in_fov, float in_fov_time, float in_fov_acceleration_time, float in_fov_deceleration_time)
|
||||
void camera::set_fov(fov_t in_fov, float in_fov_time, float in_fov_acceleration_time, float in_fov_deceleration_time)
|
||||
{
|
||||
if(in_fov_time == 0.0f && in_fov_acceleration_time == 0.0f && in_fov_deceleration_time == 0.0f)
|
||||
{
|
||||
@@ -114,26 +146,23 @@ void camera::set_fov(float in_fov, float in_fov_time, float in_fov_acceleration_
|
||||
}
|
||||
|
||||
flags &= ~CAM_STATIONARY_FOV;
|
||||
if(in_fov <= 0.0f)
|
||||
if(g3_get_hfov(in_fov) <= 0.0f)
|
||||
{
|
||||
fov.setVD(in_fov_time, in_fov_acceleration_time, 0.0f);
|
||||
}
|
||||
|
||||
fov.setAVD(in_fov, in_fov_time, in_fov_acceleration_time, in_fov_deceleration_time, 0.0f);
|
||||
fov.setAVD(g3_get_hfov(in_fov), in_fov_time, in_fov_acceleration_time, in_fov_deceleration_time, 0.0f);
|
||||
}
|
||||
|
||||
void camera::set_object_host(object *objp, int n_object_host_submodel)
|
||||
{
|
||||
if(objp == NULL)
|
||||
object_host = object_h();
|
||||
|
||||
object_host = object_h(objp);
|
||||
object_host_submodel = n_object_host_submodel;
|
||||
set_custom_position_function(NULL);
|
||||
set_custom_orientation_function(NULL);
|
||||
if(n_object_host_submodel > 0)
|
||||
{
|
||||
if(objp->type == OBJ_SHIP)
|
||||
if(objp != nullptr && objp->type == OBJ_SHIP)
|
||||
{
|
||||
ship_subsys* ssp = GET_FIRST(&Ships[objp->instance].subsys_list);
|
||||
while ( ssp != END_OF_LIST( &Ships[objp->instance].subsys_list ) )
|
||||
@@ -319,11 +348,14 @@ int camera::get_object_target_submodel()
|
||||
return object_target_submodel;
|
||||
}
|
||||
|
||||
float camera::get_fov()
|
||||
fov_t camera::get_fov()
|
||||
{
|
||||
if(!(flags & CAM_STATIONARY_FOV))
|
||||
{
|
||||
fov.get(&c_fov, NULL);
|
||||
float fov_now;
|
||||
fov.get(&fov_now, nullptr);
|
||||
return fov_now;
|
||||
//TODO enable moving asymmetric fov
|
||||
}
|
||||
|
||||
return c_fov;
|
||||
|
||||
+18
-5
@@ -10,6 +10,8 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <mpark/variant.hpp>
|
||||
|
||||
#define CAM_STATIONARY_FOV (1<<0)
|
||||
#define CAM_STATIONARY_ORI (1<<1)
|
||||
#define CAM_STATIONARY_POS (1<<2)
|
||||
@@ -18,6 +20,17 @@
|
||||
#define EXTERN_CAM_BBOX_CONSTANT_PADDING 5.0f
|
||||
#define EXTERN_CAM_BBOX_MULTIPLIER_PADDING 1.5f
|
||||
|
||||
struct asymmetric_fov {
|
||||
float left, right, up, down;
|
||||
friend asymmetric_fov operator* (const asymmetric_fov&, const float&);
|
||||
friend asymmetric_fov operator+ (const asymmetric_fov&, const float&);
|
||||
friend asymmetric_fov operator- (const asymmetric_fov&, const float&);
|
||||
};
|
||||
using fov_t = mpark::variant<float, asymmetric_fov>;
|
||||
fov_t operator* (const fov_t&, const float&);
|
||||
fov_t operator+ (const fov_t&, const float&);
|
||||
fov_t operator- (const fov_t&, const float&);
|
||||
|
||||
class camera
|
||||
{
|
||||
protected:
|
||||
@@ -41,7 +54,7 @@ protected:
|
||||
avd_movement ori[9];
|
||||
|
||||
//Cache stuff
|
||||
float c_fov;
|
||||
fov_t c_fov;
|
||||
vec3d c_pos;
|
||||
matrix c_ori;
|
||||
public:
|
||||
@@ -59,7 +72,7 @@ public:
|
||||
void set_custom_position_function(void (*n_func_custom_position)(camera *cam, vec3d *pos));
|
||||
void set_custom_orientation_function(void (*n_func_custom_orientation)(camera *cam, matrix *ori));
|
||||
|
||||
void set_fov(float in_fov, float in_fov_time = 0.0f, float in_fov_acceleration_time = 0.0f, float in_deceleration_time = 0.0f);
|
||||
void set_fov(fov_t in_fov, float in_fov_time = 0.0f, float in_fov_acceleration_time = 0.0f, float in_deceleration_time = 0.0f);
|
||||
|
||||
void set_position(vec3d *in_position = NULL, float in_translation_time = 0.0f, float in_translation_acceleration_time = 0.0f, float in_translation_deceleration_time = 0.0f, float in_end_velocity = 0.0f);
|
||||
|
||||
@@ -74,7 +87,7 @@ public:
|
||||
int get_object_host_submodel();
|
||||
object *get_object_target();
|
||||
int get_object_target_submodel();
|
||||
float get_fov();
|
||||
fov_t get_fov();
|
||||
void get_info(vec3d *position, matrix *orientation, bool apply_camera_orientation = true);
|
||||
|
||||
//Is
|
||||
@@ -155,8 +168,8 @@ public:
|
||||
|
||||
//Some global stuff
|
||||
extern SCP_vector<subtitle> Subtitles;
|
||||
extern float VIEWER_ZOOM_DEFAULT;
|
||||
extern float COCKPIT_ZOOM_DEFAULT;
|
||||
extern fov_t VIEWER_ZOOM_DEFAULT;
|
||||
extern fov_t COCKPIT_ZOOM_DEFAULT;
|
||||
extern float Sexp_fov;
|
||||
|
||||
//Helpful functions
|
||||
|
||||
@@ -438,7 +438,7 @@ int cfile_flush_dir(int dir_type)
|
||||
// filename = name of filename or filepath to process
|
||||
// ext = extension to add. Must start with the period
|
||||
// Returns: new filename or filepath with extension.
|
||||
char *cf_add_ext(const char *filename, const char *ext)
|
||||
const char *cf_add_ext(const char *filename, const char *ext)
|
||||
{
|
||||
static char path[MAX_PATH_LEN];
|
||||
|
||||
|
||||
+1
-1
@@ -171,7 +171,7 @@ int cfile_init(const char *exe_dir, const char *cdrom_dir=NULL);
|
||||
void cfile_close();
|
||||
|
||||
// add an extension to a filename if it doesn't already have it
|
||||
char *cf_add_ext(const char *filename, const char *ext);
|
||||
const char *cf_add_ext(const char *filename, const char *ext);
|
||||
|
||||
// return filename of a CFILE you called cfopen() successfully on.
|
||||
const char *cf_get_filename(const CFILE *cfile);
|
||||
|
||||
@@ -188,6 +188,7 @@ Flag exe_params[] =
|
||||
//flag launcher text FSO on_flags off_flags category reference URL
|
||||
{ "-window", "Run in window", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-window", },
|
||||
{ "-fullscreen_window", "Run in fullscreen window", false, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-fullscreen_window", },
|
||||
{ "-capture_mouse", "Capture the mouse within the window", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-capture_mouse", },
|
||||
{ "-stretch_menu", "Stretch interface to fill screen", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-stretch_menu", },
|
||||
{ "-noscalevid", "Disable scale-to-window for movies", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noscalevid", },
|
||||
{ "-nomotiondebris", "Disable motion debris", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nomotiondebris",},
|
||||
@@ -406,6 +407,7 @@ cmdline_parm use_3dwarp("-3dwarp", nullptr, AT_NONE); // Is now Fireball_use_3
|
||||
cmdline_parm use_warp_flash("-warp_flash", nullptr, AT_NONE); // Cmdline_warp_flash
|
||||
cmdline_parm allow_autpilot_interrupt("-no_ap_interrupt", nullptr, AT_NONE);
|
||||
cmdline_parm stretch_menu("-stretch_menu", nullptr, AT_NONE); // Cmdline_stretch_menu
|
||||
cmdline_parm capture_mouse("-capture_mouse", nullptr, AT_NONE); // Cmdline_capture_mouse
|
||||
cmdline_parm no_screenshake("-no_screenshake", nullptr, AT_NONE); // Cmdline_no_screenshake
|
||||
cmdline_parm deadzone("-deadzone",
|
||||
"Sets the joystick deadzone. Integer value from 0 to 100 as a percentage of the joystick's range (100% would make the stick do nothing). Disables deadzone slider in the in-game Options menu.", AT_INT); //Cmdline_deadzone
|
||||
@@ -414,6 +416,7 @@ int Cmdline_ship_choice_3d = 0;
|
||||
int Cmdline_weapon_choice_3d = 0;
|
||||
int Cmdline_autopilot_interruptable = 1;
|
||||
int Cmdline_stretch_menu = 0;
|
||||
bool Cmdline_capture_mouse = false;
|
||||
int Cmdline_no_screenshake = 0;
|
||||
int Cmdline_deadzone = -1;
|
||||
|
||||
@@ -835,7 +838,7 @@ void os_validate_parms(int argc, char *argv[])
|
||||
// if we got a -help, --help, -h, or -? then show the help text, otherwise show unknown option
|
||||
if (!stricmp(token, "-help") || !stricmp(token, "--help") || !stricmp(token, "-h") || !stricmp(token, "-?")) {
|
||||
printf("FreeSpace 2 Open, version %s\n", FS_VERSION_FULL);
|
||||
printf("Website: http://scp.indiegames.us\n");
|
||||
printf("Website: https://scp.indiegames.us\n");
|
||||
printf("Github (bug reporting): https://github.com/scp-fs2open/fs2open.github.com/issues\n\n");
|
||||
printf("Usage: fs2_open [options]\n");
|
||||
|
||||
@@ -1646,7 +1649,7 @@ bool SetCmdlineParams()
|
||||
|
||||
// be sure that this string fits in our limits
|
||||
if ( strlen(Cmdline_game_password) >= MAX_PASSWD_LEN ) {
|
||||
ReleaseWarning(LOCATION, "Multi game password is longer than max of %d charaters and will be trimmed to fit!", MAX_PASSWD_LEN-1);
|
||||
ReleaseWarning(LOCATION, "Multi game password is longer than max of %d characters and will be trimmed to fit!", MAX_PASSWD_LEN-1);
|
||||
Cmdline_game_password[MAX_PASSWD_LEN-1] = '\0';
|
||||
}
|
||||
}
|
||||
@@ -1871,6 +1874,10 @@ bool SetCmdlineParams()
|
||||
if ( stretch_menu.found() ) {
|
||||
Cmdline_stretch_menu = 1;
|
||||
}
|
||||
|
||||
if ( capture_mouse.found() ) {
|
||||
Cmdline_capture_mouse = true;
|
||||
}
|
||||
// new lighting lines
|
||||
if ( ambient_power_arg.found() )
|
||||
Cmdline_ambient_power = ambient_power_arg.get_float();
|
||||
|
||||
@@ -86,6 +86,7 @@ extern int Cmdline_ship_choice_3d;
|
||||
extern int Cmdline_weapon_choice_3d;
|
||||
extern int Cmdline_autopilot_interruptable;
|
||||
extern int Cmdline_stretch_menu;
|
||||
extern bool Cmdline_capture_mouse;
|
||||
extern int Cmdline_no_screenshake;
|
||||
extern int Cmdline_deadzone;
|
||||
|
||||
|
||||
@@ -51,6 +51,14 @@ void cmeasure_set_ship_launch_vel(object *objp, object *parent_objp, int arand)
|
||||
|
||||
objp->phys_info.max_vel.xyz.z = -25.0f;
|
||||
vm_vec_copy_scale(&objp->phys_info.desired_vel, &objp->orient.vec.fvec, objp->phys_info.max_vel.xyz.z );
|
||||
|
||||
// if this cmeasure has a single segment trail, let the trail know since we just changed the velocity
|
||||
// yeah this is hacky but that's what this function gets for CHANGING the velocity on objects with a ""CONSTANT VELOCITY""
|
||||
weapon* wp = &Weapons[objp->instance];
|
||||
if (wp->trail_ptr && wp->trail_ptr->single_segment) {
|
||||
wp->trail_ptr->vel[0] = objp->phys_info.vel;
|
||||
wp->trail_ptr->vel[1] = objp->phys_info.vel;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1359,9 +1359,6 @@ bool control_config_accept(bool API_Access)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
hud_squadmsg_save_keys(); // rebuild map for saving/restoring keys in squadmsg mode
|
||||
|
||||
if (!API_Access) {
|
||||
gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
|
||||
gamesnd_play_iface(InterfaceSounds::COMMIT_PRESSED);
|
||||
@@ -1630,7 +1627,7 @@ void control_config_close(bool API_Access)
|
||||
Ui_window.destroy();
|
||||
common_free_interface_palette(); // restore game palette
|
||||
}
|
||||
hud_squadmsg_save_keys(); // rebuild map for saving/restoring keys in squadmsg mode
|
||||
|
||||
game_flush();
|
||||
|
||||
if (Game_mode & GM_MULTIPLAYER) {
|
||||
@@ -2536,6 +2533,10 @@ void control_config_do_frame(float frametime)
|
||||
if (List_buttons[i].pressed()) {
|
||||
// Select the pressed line
|
||||
Selected_line = i + Scroll_offset;
|
||||
|
||||
// Cyborg - Quick assertion for Coverity 1093701. Not likely to happen, but we check for a negative Selected Line later.
|
||||
Assertion(Selected_line > -1, "control_config_do_frame() has somehow managed to get a negative Selected_line index of %d. Please get an SCP member.", Selected_line);
|
||||
|
||||
Selected_item = selItem::None;
|
||||
List_buttons[i].get_mouse_pos(&x, &y);
|
||||
|
||||
|
||||
@@ -45,27 +45,29 @@ int Failed_key_index;
|
||||
// Joystick configuration
|
||||
int Joy_dead_zone_size = 10;
|
||||
|
||||
auto DeadZoneOption =
|
||||
options::OptionBuilder<int>("Input.JoystickDeadZone", "Deadzone", "The deadzone of the selected joystick.")
|
||||
.category("Input")
|
||||
.range(0, 45)
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.default_val(10)
|
||||
.bind_to(&Joy_dead_zone_size)
|
||||
.importance(1)
|
||||
.finish();
|
||||
auto DeadZoneOption = options::OptionBuilder<int>("Input.JoystickDeadZone",
|
||||
std::pair<const char*, int>{"Deadzone", 1377},
|
||||
std::pair<const char*, int>{"The deadzone used for all joysticks", 1744})
|
||||
.category("Input")
|
||||
.range(0, 45)
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.default_val(10)
|
||||
.bind_to(&Joy_dead_zone_size)
|
||||
.importance(1)
|
||||
.finish();
|
||||
|
||||
int Joy_sensitivity = 9;
|
||||
|
||||
auto SensitivityOption =
|
||||
options::OptionBuilder<int>("Input.JoystickSensitivity", "Sensitivity", "The sentitivity of the selected joystick.")
|
||||
.category("Input")
|
||||
.range(0, 9)
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.default_val(9)
|
||||
.bind_to(&Joy_sensitivity)
|
||||
.importance(2)
|
||||
.finish();
|
||||
auto SensitivityOption = options::OptionBuilder<int>("Input.JoystickSensitivity",
|
||||
std::pair<const char*, int>{"Sensitivity", 1745},
|
||||
std::pair<const char*, int>{"The sensitivity used for all joysticks", 1746})
|
||||
.category("Input")
|
||||
.range(0, 9)
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.default_val(9)
|
||||
.bind_to(&Joy_sensitivity)
|
||||
.importance(2)
|
||||
.finish();
|
||||
|
||||
//! arrays which hold the key mappings. The array index represents a key-independent action.
|
||||
//! please use SPACES for aligning the fields of this array
|
||||
@@ -158,8 +160,8 @@ void control_config_common_init_bindings() {
|
||||
// flight controls (flight modes)
|
||||
(BANK_WHEN_PRESSED, -1, -1, SHIP_TAB, 1, "Bank When Pressed", CC_TYPE_CONTINUOUS)
|
||||
(AFTERBURNER, KEY_TAB, 5, SHIP_TAB, 1, "Afterburner", CC_TYPE_CONTINUOUS)
|
||||
(GLIDE_WHEN_PRESSED, -1, -1, SHIP_TAB, 0, "Glide When Pressed", CC_TYPE_CONTINUOUS)
|
||||
(TOGGLE_GLIDING, KEY_ALTED | KEY_G, -1, SHIP_TAB, 0, "Toggle Gliding", CC_TYPE_TRIGGER)
|
||||
(GLIDE_WHEN_PRESSED, -1, -1, SHIP_TAB, 1774, "Glide When Pressed", CC_TYPE_CONTINUOUS)
|
||||
(TOGGLE_GLIDING, KEY_ALTED | KEY_G, -1, SHIP_TAB, 1775, "Toggle Gliding", CC_TYPE_TRIGGER)
|
||||
|
||||
// flight controls (axes)
|
||||
(JOY_HEADING_AXIS, JOY_X_AXIS, MOUSE_X_AXIS, SHIP_TAB, 1016, "Turn (Yaw) Axis", CC_TYPE_AXIS_REL)
|
||||
@@ -173,7 +175,7 @@ void control_config_common_init_bindings() {
|
||||
(FIRE_SECONDARY, KEY_SPACEBAR, 1, WEAPON_TAB, 1, "Fire Secondary Weapon", CC_TYPE_CONTINUOUS)
|
||||
(CYCLE_NEXT_PRIMARY, KEY_PERIOD, -1, WEAPON_TAB, 1, "Cycle Primary Weapon Forward", CC_TYPE_TRIGGER)
|
||||
(CYCLE_PREV_PRIMARY, KEY_COMMA, -1, WEAPON_TAB, 1, "Cycle Primary Weapon Backward", CC_TYPE_TRIGGER)
|
||||
(CYCLE_PRIMARY_WEAPON_SEQUENCE, KEY_O, -1, WEAPON_TAB, 0, "Cycle Primary Weapon Firing Rate", CC_TYPE_TRIGGER)
|
||||
(CYCLE_PRIMARY_WEAPON_SEQUENCE, KEY_O, -1, WEAPON_TAB, 1776, "Cycle Primary Weapon Firing Rate", CC_TYPE_TRIGGER)
|
||||
(CYCLE_SECONDARY, KEY_DIVIDE, -1, WEAPON_TAB, 1, "Cycle Secondary Weapon Forward", CC_TYPE_TRIGGER)
|
||||
(CYCLE_NUM_MISSLES, KEY_SHIFTED | KEY_DIVIDE, -1, WEAPON_TAB, 1, "Cycle Secondary Weapon Firing Rate", CC_TYPE_TRIGGER)
|
||||
(LAUNCH_COUNTERMEASURE, KEY_X, 3, WEAPON_TAB, 1, "Launch Countermeasure", CC_TYPE_TRIGGER)
|
||||
@@ -209,8 +211,8 @@ void control_config_common_init_bindings() {
|
||||
(PADLOCK_DOWN, -1, 32, COMPUTER_TAB, 1, "View Rear", CC_TYPE_CONTINUOUS)
|
||||
(PADLOCK_LEFT, -1, 34, COMPUTER_TAB, 1, "View Left", CC_TYPE_CONTINUOUS)
|
||||
(PADLOCK_RIGHT, -1, 35, COMPUTER_TAB, 1, "View Right", CC_TYPE_CONTINUOUS)
|
||||
(VIEW_TOPDOWN, -1, -1, COMPUTER_TAB, 0, "Top-Down View", CC_TYPE_TRIGGER)
|
||||
(VIEW_TRACK_TARGET, -1, -1, COMPUTER_TAB, 0, "Target Padlock View", CC_TYPE_TRIGGER)
|
||||
(VIEW_TOPDOWN, -1, -1, COMPUTER_TAB, 1777, "Top-Down View", CC_TYPE_TRIGGER)
|
||||
(VIEW_TRACK_TARGET, -1, -1, COMPUTER_TAB, 1778, "Target Padlock View", CC_TYPE_TRIGGER)
|
||||
|
||||
(RADAR_RANGE_CYCLE, KEY_RAPOSTRO, -1, COMPUTER_TAB, 1, "Cycle Radar Range", CC_TYPE_TRIGGER)
|
||||
(SQUADMSG_MENU, KEY_C, -1, COMPUTER_TAB, 1, "Communications Menu", CC_TYPE_TRIGGER)
|
||||
@@ -235,8 +237,8 @@ void control_config_common_init_bindings() {
|
||||
|
||||
// Navigation and Autopilot
|
||||
(SHOW_NAVMAP, -1, -1, NO_TAB, 1, "Show Nav Map", CC_TYPE_TRIGGER, true)
|
||||
(AUTO_PILOT_TOGGLE, KEY_ALTED | KEY_A, -1, COMPUTER_TAB, 0, "Toggle Auto Pilot", CC_TYPE_TRIGGER)
|
||||
(NAV_CYCLE, KEY_ALTED | KEY_N, -1, COMPUTER_TAB, 0, "Cycle Nav Points", CC_TYPE_TRIGGER)
|
||||
(AUTO_PILOT_TOGGLE, KEY_ALTED | KEY_A, -1, COMPUTER_TAB, 1779, "Toggle Auto Pilot", CC_TYPE_TRIGGER)
|
||||
(NAV_CYCLE, KEY_ALTED | KEY_N, -1, COMPUTER_TAB, 1780, "Cycle Nav Points", CC_TYPE_TRIGGER)
|
||||
|
||||
// Escort
|
||||
(ADD_REMOVE_ESCORT, KEY_ALTED | KEY_E, -1, COMPUTER_TAB, 1, "Add or Remove Escort", CC_TYPE_TRIGGER)
|
||||
@@ -258,7 +260,7 @@ void control_config_common_init_bindings() {
|
||||
// HUD
|
||||
(TOGGLE_HUD, KEY_SHIFTED | KEY_O, -1, COMPUTER_TAB, 1, "Toggle HUD", CC_TYPE_TRIGGER)
|
||||
(TOGGLE_HUD_CONTRAST, KEY_L, -1, COMPUTER_TAB, 1, "Toggle High HUD Contrast", CC_TYPE_TRIGGER)
|
||||
(TOGGLE_HUD_SHADOWS, KEY_ALTED | KEY_L, -1, COMPUTER_TAB, 0, "Toggle HUD Drop Shadows", CC_TYPE_TRIGGER)
|
||||
(TOGGLE_HUD_SHADOWS, KEY_ALTED | KEY_L, -1, COMPUTER_TAB, 1781, "Toggle HUD Drop Shadows", CC_TYPE_TRIGGER)
|
||||
(HUD_TARGETBOX_TOGGLE_WIREFRAME, KEY_ALTED | KEY_SHIFTED | KEY_Q, -1, COMPUTER_TAB, 1, "Toggle HUD Wireframe Target View", CC_TYPE_TRIGGER)
|
||||
|
||||
// Custom Controls
|
||||
@@ -799,6 +801,8 @@ void control_config_common_init()
|
||||
Mouse_button_text[6] = vm_strdup(XSTR("Wheel Down", 1656));
|
||||
Mouse_button_text[7] = vm_strdup(XSTR("Wheel Left", 1657));
|
||||
Mouse_button_text[8] = vm_strdup(XSTR("Wheel Right", 1658));
|
||||
|
||||
Script_system.OnStateDestroy.add([](lua_State*) -> void { Lua_hooks.clear(); });
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -108,7 +108,7 @@ class Decoder {
|
||||
* @note A implementation should initialize the datastructures required for decoding here.
|
||||
*
|
||||
* @param fileName The name of the file that should be opened
|
||||
* @return @c true if the initialization was successfull, @c false otherwise
|
||||
* @return @c true if the initialization was successful, @c false otherwise
|
||||
*/
|
||||
virtual bool initialize(const SCP_string& fileName, const PlaybackProperties& properties) = 0;
|
||||
|
||||
|
||||
@@ -174,10 +174,15 @@ void determine_display_positions(Player* player, PlaybackState* state) {
|
||||
void initialize_player_state(Player* player, PlaybackState* state) {
|
||||
determine_display_positions(player, state);
|
||||
|
||||
state->subtitle_font = font::FontManager::getFontIndex(Movie_subtitle_font);
|
||||
if (!Movie_subtitle_font.empty()) {
|
||||
state->subtitle_font = font::FontManager::getFontIndex(Movie_subtitle_font);
|
||||
|
||||
if (state->subtitle_font < 0) {
|
||||
Warning(LOCATION, "Failed to load subtitle font '%s'! Subtitles will be disabled.", Movie_subtitle_font.c_str());
|
||||
if (state->subtitle_font < 0) {
|
||||
Warning(LOCATION, "Failed to load subtitle font '%s'! Subtitles will be disabled.", Movie_subtitle_font.c_str());
|
||||
}
|
||||
}
|
||||
else if (font::FontManager::numberOfFonts() > 0) {
|
||||
state->subtitle_font = 0; // if not explicitly specified, default to the first available font
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@
|
||||
* half-rate linear filtering on GCN.
|
||||
*
|
||||
* If SMAA is applied to 64-bit color buffers, switching to point filtering
|
||||
* when accesing them will increase the performance. Search for
|
||||
* when accessing them will increase the performance. Search for
|
||||
* 'SMAASamplePoint' to see which textures may benefit from point
|
||||
* filtering, and where (which is basically the color input in the edge
|
||||
* detection and resolve passes).
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
|
||||
#include "shadows.sdr" //! #include "shadows.sdr"
|
||||
|
||||
in vec3 beamVec;
|
||||
in vec3 lightPosition;
|
||||
out vec4 fragOut0;
|
||||
|
||||
uniform sampler2D ColorBuffer;
|
||||
@@ -26,6 +24,13 @@ layout (std140) uniform globalDeferredData {
|
||||
|
||||
float invScreenWidth;
|
||||
float invScreenHeight;
|
||||
|
||||
float nearPlane;
|
||||
};
|
||||
|
||||
layout (std140) uniform matrixData {
|
||||
mat4 modelViewMatrix;
|
||||
mat4 projMatrix;
|
||||
};
|
||||
|
||||
layout (std140) uniform lightData {
|
||||
@@ -63,23 +68,24 @@ vec3 ExpandLightSize(in vec3 lightDir, in vec3 reflectDir) {
|
||||
vec3 centerToRay = max(dot(lightDir, reflectDir),sourceRadius) * reflectDir - lightDir;
|
||||
return lightDir + centerToRay * clamp(sourceRadius/length(centerToRay), 0.0, 1.0);
|
||||
}
|
||||
void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 lightDir, out float attenuation, out float area_normalisation)
|
||||
void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 lightDirOut, out float attenuation, out float area_normalisation)
|
||||
{
|
||||
if (lightType == LT_DIRECTIONAL) {
|
||||
lightDir = normalize(lightPosition);
|
||||
lightDirOut = normalize(lightDir);
|
||||
attenuation = 1.0;
|
||||
area_normalisation = 1.0;
|
||||
} else {
|
||||
vec3 lightPosition = modelViewMatrix[3].xyz;
|
||||
// Positional light source
|
||||
if (lightType == LT_POINT) {
|
||||
lightDir = lightPosition - position.xyz;
|
||||
float dist = length(lightDir);
|
||||
lightDirOut = lightPosition - position.xyz;
|
||||
float dist = length(lightDirOut);
|
||||
|
||||
// this chunk is unneccessary if sourceRadius= 0.0, but let's avoid a branch.
|
||||
// given a sphere of radius sourceRadius centered at lightDir,
|
||||
// move lightDir towards the ray defined by reflectDir
|
||||
lightDir = ExpandLightSize(lightDir, reflectDir);
|
||||
dist = length(lightDir);
|
||||
// this chunk is unnecessary if sourceRadius= 0.0, but let's avoid a branch.
|
||||
// given a sphere of radius sourceRadius centered at lightDirOut,
|
||||
// move lightDirOut towards the ray defined by reflectDir
|
||||
lightDirOut = ExpandLightSize(lightDirOut, reflectDir);
|
||||
dist = length(lightDirOut);
|
||||
// Energy conservation term
|
||||
float alpha_adjust = clamp(alpha + (sourceRadius/(2*dist)), 0.0, 1.0);
|
||||
area_normalisation = alpha/alpha_adjust;
|
||||
@@ -93,7 +99,7 @@ void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 li
|
||||
attenuation = 1.0 - clamp(sqrt(dist / lightRadius), 0.0, 1.0);
|
||||
}
|
||||
else if (lightType == LT_TUBE) { // Tube light
|
||||
|
||||
vec3 beamVec = vec3(modelViewMatrix * vec4(0.0, 0.0, -scale.z, 0.0));
|
||||
vec3 beamDir = normalize(beamVec);
|
||||
//The actual 'lighting element' is shorter than the light volume cylinder
|
||||
//To compensate the light is moved forward along the beam one radius and the length shortened
|
||||
@@ -113,15 +119,15 @@ void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 li
|
||||
vec3 r = d - a_t * dot(d, a_t) - c * dot(d,c);
|
||||
float neardist = dot(r, r)/dot(b_t, r);
|
||||
// Move along the beam by the distance we calculated
|
||||
lightDir = sourceDir - beamDir * clamp(neardist, 0.0, beamLength);
|
||||
lightDirOut = sourceDir - beamDir * clamp(neardist, 0.0, beamLength);
|
||||
// Somebody with a symbolic expression simplifier or a wrinklier brain than me
|
||||
// should figure out how to optimise these calcs - qaz
|
||||
|
||||
|
||||
// this chunk is unneccessary if sourceRadius = 0.0, but let's avoid a branch.
|
||||
// this chunk is unnecessary if sourceRadius = 0.0, but let's avoid a branch.
|
||||
// Same principle as in LT_POINT, treat chosen location as a spherelight.
|
||||
lightDir = ExpandLightSize(lightDir, reflectDir);
|
||||
float dist = length(lightDir);
|
||||
lightDirOut = ExpandLightSize(lightDirOut, reflectDir);
|
||||
float dist = length(lightDirOut);
|
||||
// Energy conservation term
|
||||
float alpha_adjust = min(alpha + (sourceRadius/(2*dist)), 1.0);
|
||||
area_normalisation = alpha/alpha_adjust;
|
||||
@@ -134,9 +140,9 @@ void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 li
|
||||
attenuation = 1.0 - clamp(sqrt(dist / lightRadius), 0.0, 1.0);
|
||||
}
|
||||
else if (lightType == LT_CONE) {
|
||||
lightDir = lightPosition - position.xyz;
|
||||
float coneDot = dot(normalize(-lightDir), coneDir);
|
||||
float dist = length(lightDir);
|
||||
lightDirOut = lightPosition - position.xyz;
|
||||
float coneDot = dot(normalize(-lightDirOut), coneDir);
|
||||
float dist = length(lightDirOut);
|
||||
attenuation = 1.0 - clamp(sqrt(dist / lightRadius), 0.0, 1.0);
|
||||
area_normalisation = 1.0;
|
||||
|
||||
@@ -155,7 +161,7 @@ void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 li
|
||||
}
|
||||
}
|
||||
attenuation *= attenuation;
|
||||
lightDir = normalize(lightDir);
|
||||
lightDirOut = normalize(lightDirOut);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,7 +170,7 @@ void main()
|
||||
vec2 screenPos = gl_FragCoord.xy * vec2(invScreenWidth, invScreenHeight);
|
||||
vec3 position = texture(PositionBuffer, screenPos).xyz;
|
||||
|
||||
if(abs(dot(position, position)) < 0.1)
|
||||
if(abs(dot(position, position)) < nearPlane * nearPlane)
|
||||
discard;
|
||||
|
||||
vec3 diffColor = texture(ColorBuffer, screenPos).rgb;
|
||||
|
||||
@@ -27,17 +27,11 @@ layout (std140) uniform lightData {
|
||||
float sourceRadius;
|
||||
};
|
||||
|
||||
out vec3 lightPosition;
|
||||
out vec3 beamVec;
|
||||
void main()
|
||||
{
|
||||
if (lightType == LT_DIRECTIONAL) {
|
||||
gl_Position = vec4(vertPosition.xyz, 1.0);
|
||||
lightPosition = lightDir;
|
||||
} else {
|
||||
gl_Position = projMatrix * modelViewMatrix * vec4(vertPosition.xyz * scale, 1.0);
|
||||
lightPosition = modelViewMatrix[3].xyz;
|
||||
if(lightType == LT_TUBE)
|
||||
beamVec = vec3(modelViewMatrix * vec4(0.0, 0.0, -scale.z, 0.0));
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ in vec4 fragTexCoord;
|
||||
|
||||
out vec4 fragOut0;
|
||||
|
||||
// Iteratively optimised points to give low discrepancy distribution on arbritrary hemisphere.
|
||||
// Iteratively optimised points to give low discrepancy distribution on arbitrary hemisphere.
|
||||
const vec3 points[128] = vec3[128](
|
||||
vec3(-0.2268, 0.6185, 0.7523),
|
||||
vec3( 0.9958, -0.0871, -0.0277),
|
||||
|
||||
@@ -33,7 +33,7 @@ vec3 ComputeGGX(vec3 specColor, vec3 diffColor, vec3 light, vec3 normal, vec3 ha
|
||||
|
||||
// NOTE - we're intentionally using UE4's reflectance model as modellers are using tools designed for common engines.
|
||||
|
||||
// Cook-Torrance BRDF Model (Specular Reflection) = Distibution * Fresnel * Geometry / (4*dotNV*dotNL)
|
||||
// Cook-Torrance BRDF Model (Specular Reflection) = Distribution * Fresnel * Geometry / (4*dotNV*dotNL)
|
||||
|
||||
// Distribution Term - Trowbridge-Reitz GGX
|
||||
|
||||
@@ -49,7 +49,7 @@ vec3 ComputeGGX(vec3 specColor, vec3 diffColor, vec3 light, vec3 normal, vec3 ha
|
||||
// Smith's method:
|
||||
// Microsurfaces block light rays coming in from the light
|
||||
// AND block light rays reflecting to the camera.
|
||||
// Hence, model both seperately and multiply.
|
||||
// Hence, model both separately and multiply.
|
||||
float g1vNL = GeometrySchlickGGX(dotNL, k);
|
||||
float g1vNV = GeometrySchlickGGX(dotNV, k);
|
||||
float geometry = g1vNL * g1vNV;
|
||||
|
||||
@@ -0,0 +1,714 @@
|
||||
-- Module options:
|
||||
local always_try_using_lpeg = true
|
||||
local register_global_module_table = false
|
||||
local global_module_name = 'json'
|
||||
|
||||
--[==[
|
||||
|
||||
David Kolf's JSON module for Lua 5.1/5.2
|
||||
|
||||
Version 2.5
|
||||
|
||||
|
||||
For the documentation see the corresponding readme.txt or visit
|
||||
<http://dkolf.de/src/dkjson-lua.fsl/>.
|
||||
|
||||
You can contact the author by sending an e-mail to 'david' at the
|
||||
domain 'dkolf.de'.
|
||||
|
||||
|
||||
Copyright (C) 2010-2014 David Heiko Kolf
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
--]==]
|
||||
|
||||
-- global dependencies:
|
||||
local pairs, type, tostring, tonumber, getmetatable, setmetatable, rawset =
|
||||
pairs, type, tostring, tonumber, getmetatable, setmetatable, rawset
|
||||
local error, require, pcall, select = error, require, pcall, select
|
||||
local floor, huge = math.floor, math.huge
|
||||
local strrep, gsub, strsub, strbyte, strchar, strfind, strlen, strformat =
|
||||
string.rep, string.gsub, string.sub, string.byte, string.char,
|
||||
string.find, string.len, string.format
|
||||
local strmatch = string.match
|
||||
local concat = table.concat
|
||||
|
||||
local json = { version = "dkjson 2.5" }
|
||||
|
||||
if register_global_module_table then
|
||||
_G[global_module_name] = json
|
||||
end
|
||||
|
||||
local _ENV = nil -- blocking globals in Lua 5.2
|
||||
|
||||
pcall (function()
|
||||
-- Enable access to blocked metatables.
|
||||
-- Don't worry, this module doesn't change anything in them.
|
||||
local debmeta = require "debug".getmetatable
|
||||
if debmeta then getmetatable = debmeta end
|
||||
end)
|
||||
|
||||
json.null = setmetatable ({}, {
|
||||
__tojson = function () return "null" end
|
||||
})
|
||||
|
||||
local function isarray (tbl)
|
||||
local max, n, arraylen = 0, 0, 0
|
||||
for k,v in pairs (tbl) do
|
||||
if k == 'n' and type(v) == 'number' then
|
||||
arraylen = v
|
||||
if v > max then
|
||||
max = v
|
||||
end
|
||||
else
|
||||
if type(k) ~= 'number' or k < 1 or floor(k) ~= k then
|
||||
return false
|
||||
end
|
||||
if k > max then
|
||||
max = k
|
||||
end
|
||||
n = n + 1
|
||||
end
|
||||
end
|
||||
if max > 10 and max > arraylen and max > n * 2 then
|
||||
return false -- don't create an array with too many holes
|
||||
end
|
||||
return true, max
|
||||
end
|
||||
|
||||
local escapecodes = {
|
||||
["\""] = "\\\"", ["\\"] = "\\\\", ["\b"] = "\\b", ["\f"] = "\\f",
|
||||
["\n"] = "\\n", ["\r"] = "\\r", ["\t"] = "\\t"
|
||||
}
|
||||
|
||||
local function escapeutf8 (uchar)
|
||||
local value = escapecodes[uchar]
|
||||
if value then
|
||||
return value
|
||||
end
|
||||
local a, b, c, d = strbyte (uchar, 1, 4)
|
||||
a, b, c, d = a or 0, b or 0, c or 0, d or 0
|
||||
if a <= 0x7f then
|
||||
value = a
|
||||
elseif 0xc0 <= a and a <= 0xdf and b >= 0x80 then
|
||||
value = (a - 0xc0) * 0x40 + b - 0x80
|
||||
elseif 0xe0 <= a and a <= 0xef and b >= 0x80 and c >= 0x80 then
|
||||
value = ((a - 0xe0) * 0x40 + b - 0x80) * 0x40 + c - 0x80
|
||||
elseif 0xf0 <= a and a <= 0xf7 and b >= 0x80 and c >= 0x80 and d >= 0x80 then
|
||||
value = (((a - 0xf0) * 0x40 + b - 0x80) * 0x40 + c - 0x80) * 0x40 + d - 0x80
|
||||
else
|
||||
return ""
|
||||
end
|
||||
if value <= 0xffff then
|
||||
return strformat ("\\u%.4x", value)
|
||||
elseif value <= 0x10ffff then
|
||||
-- encode as UTF-16 surrogate pair
|
||||
value = value - 0x10000
|
||||
local highsur, lowsur = 0xD800 + floor (value/0x400), 0xDC00 + (value % 0x400)
|
||||
return strformat ("\\u%.4x\\u%.4x", highsur, lowsur)
|
||||
else
|
||||
return ""
|
||||
end
|
||||
end
|
||||
|
||||
local function fsub (str, pattern, repl)
|
||||
-- gsub always builds a new string in a buffer, even when no match
|
||||
-- exists. First using find should be more efficient when most strings
|
||||
-- don't contain the pattern.
|
||||
if strfind (str, pattern) then
|
||||
return gsub (str, pattern, repl)
|
||||
else
|
||||
return str
|
||||
end
|
||||
end
|
||||
|
||||
local function quotestring (value)
|
||||
-- based on the regexp "escapable" in https://github.com/douglascrockford/JSON-js
|
||||
value = fsub (value, "[%z\1-\31\"\\\127]", escapeutf8)
|
||||
if strfind (value, "[\194\216\220\225\226\239]") then
|
||||
value = fsub (value, "\194[\128-\159\173]", escapeutf8)
|
||||
value = fsub (value, "\216[\128-\132]", escapeutf8)
|
||||
value = fsub (value, "\220\143", escapeutf8)
|
||||
value = fsub (value, "\225\158[\180\181]", escapeutf8)
|
||||
value = fsub (value, "\226\128[\140-\143\168-\175]", escapeutf8)
|
||||
value = fsub (value, "\226\129[\160-\175]", escapeutf8)
|
||||
value = fsub (value, "\239\187\191", escapeutf8)
|
||||
value = fsub (value, "\239\191[\176-\191]", escapeutf8)
|
||||
end
|
||||
return "\"" .. value .. "\""
|
||||
end
|
||||
json.quotestring = quotestring
|
||||
|
||||
local function replace(str, o, n)
|
||||
local i, j = strfind (str, o, 1, true)
|
||||
if i then
|
||||
return strsub(str, 1, i-1) .. n .. strsub(str, j+1, -1)
|
||||
else
|
||||
return str
|
||||
end
|
||||
end
|
||||
|
||||
-- locale independent num2str and str2num functions
|
||||
local decpoint, numfilter
|
||||
|
||||
local function updatedecpoint ()
|
||||
decpoint = strmatch(tostring(0.5), "([^05+])")
|
||||
-- build a filter that can be used to remove group separators
|
||||
numfilter = "[^0-9%-%+eE" .. gsub(decpoint, "[%^%$%(%)%%%.%[%]%*%+%-%?]", "%%%0") .. "]+"
|
||||
end
|
||||
|
||||
updatedecpoint()
|
||||
|
||||
local function num2str (num)
|
||||
return replace(fsub(tostring(num), numfilter, ""), decpoint, ".")
|
||||
end
|
||||
|
||||
local function str2num (str)
|
||||
local num = tonumber(replace(str, ".", decpoint))
|
||||
if not num then
|
||||
updatedecpoint()
|
||||
num = tonumber(replace(str, ".", decpoint))
|
||||
end
|
||||
return num
|
||||
end
|
||||
|
||||
local function addnewline2 (level, buffer, buflen)
|
||||
buffer[buflen+1] = "\n"
|
||||
buffer[buflen+2] = strrep (" ", level)
|
||||
buflen = buflen + 2
|
||||
return buflen
|
||||
end
|
||||
|
||||
function json.addnewline (state)
|
||||
if state.indent then
|
||||
state.bufferlen = addnewline2 (state.level or 0,
|
||||
state.buffer, state.bufferlen or #(state.buffer))
|
||||
end
|
||||
end
|
||||
|
||||
local encode2 -- forward declaration
|
||||
|
||||
local function addpair (key, value, prev, indent, level, buffer, buflen, tables, globalorder, state)
|
||||
local kt = type (key)
|
||||
if kt ~= 'string' and kt ~= 'number' then
|
||||
return nil, "type '" .. kt .. "' is not supported as a key by JSON."
|
||||
end
|
||||
if prev then
|
||||
buflen = buflen + 1
|
||||
buffer[buflen] = ","
|
||||
end
|
||||
if indent then
|
||||
buflen = addnewline2 (level, buffer, buflen)
|
||||
end
|
||||
buffer[buflen+1] = quotestring (key)
|
||||
buffer[buflen+2] = ":"
|
||||
return encode2 (value, indent, level, buffer, buflen + 2, tables, globalorder, state)
|
||||
end
|
||||
|
||||
local function appendcustom(res, buffer, state)
|
||||
local buflen = state.bufferlen
|
||||
if type (res) == 'string' then
|
||||
buflen = buflen + 1
|
||||
buffer[buflen] = res
|
||||
end
|
||||
return buflen
|
||||
end
|
||||
|
||||
local function exception(reason, value, state, buffer, buflen, defaultmessage)
|
||||
defaultmessage = defaultmessage or reason
|
||||
local handler = state.exception
|
||||
if not handler then
|
||||
return nil, defaultmessage
|
||||
else
|
||||
state.bufferlen = buflen
|
||||
local ret, msg = handler (reason, value, state, defaultmessage)
|
||||
if not ret then return nil, msg or defaultmessage end
|
||||
return appendcustom(ret, buffer, state)
|
||||
end
|
||||
end
|
||||
|
||||
function json.encodeexception(reason, value, state, defaultmessage)
|
||||
return quotestring("<" .. defaultmessage .. ">")
|
||||
end
|
||||
|
||||
encode2 = function (value, indent, level, buffer, buflen, tables, globalorder, state)
|
||||
local valtype = type (value)
|
||||
local valmeta = getmetatable (value)
|
||||
valmeta = type (valmeta) == 'table' and valmeta -- only tables
|
||||
local valtojson = valmeta and valmeta.__tojson
|
||||
if valtojson then
|
||||
if tables[value] then
|
||||
return exception('reference cycle', value, state, buffer, buflen)
|
||||
end
|
||||
tables[value] = true
|
||||
state.bufferlen = buflen
|
||||
local ret, msg = valtojson (value, state)
|
||||
if not ret then return exception('custom encoder failed', value, state, buffer, buflen, msg) end
|
||||
tables[value] = nil
|
||||
buflen = appendcustom(ret, buffer, state)
|
||||
elseif value == nil then
|
||||
buflen = buflen + 1
|
||||
buffer[buflen] = "null"
|
||||
elseif valtype == 'number' then
|
||||
local s
|
||||
if value ~= value or value >= huge or -value >= huge then
|
||||
-- This is the behaviour of the original JSON implementation.
|
||||
s = "null"
|
||||
else
|
||||
s = num2str (value)
|
||||
end
|
||||
buflen = buflen + 1
|
||||
buffer[buflen] = s
|
||||
elseif valtype == 'boolean' then
|
||||
buflen = buflen + 1
|
||||
buffer[buflen] = value and "true" or "false"
|
||||
elseif valtype == 'string' then
|
||||
buflen = buflen + 1
|
||||
buffer[buflen] = quotestring (value)
|
||||
elseif valtype == 'table' then
|
||||
if tables[value] then
|
||||
return exception('reference cycle', value, state, buffer, buflen)
|
||||
end
|
||||
tables[value] = true
|
||||
level = level + 1
|
||||
local isa, n = isarray (value)
|
||||
if n == 0 and valmeta and valmeta.__jsontype == 'object' then
|
||||
isa = false
|
||||
end
|
||||
local msg
|
||||
if isa then -- JSON array
|
||||
buflen = buflen + 1
|
||||
buffer[buflen] = "["
|
||||
for i = 1, n do
|
||||
buflen, msg = encode2 (value[i], indent, level, buffer, buflen, tables, globalorder, state)
|
||||
if not buflen then return nil, msg end
|
||||
if i < n then
|
||||
buflen = buflen + 1
|
||||
buffer[buflen] = ","
|
||||
end
|
||||
end
|
||||
buflen = buflen + 1
|
||||
buffer[buflen] = "]"
|
||||
else -- JSON object
|
||||
local prev = false
|
||||
buflen = buflen + 1
|
||||
buffer[buflen] = "{"
|
||||
local order = valmeta and valmeta.__jsonorder or globalorder
|
||||
if order then
|
||||
local used = {}
|
||||
n = #order
|
||||
for i = 1, n do
|
||||
local k = order[i]
|
||||
local v = value[k]
|
||||
if v then
|
||||
used[k] = true
|
||||
buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder, state)
|
||||
prev = true -- add a seperator before the next element
|
||||
end
|
||||
end
|
||||
for k,v in pairs (value) do
|
||||
if not used[k] then
|
||||
buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder, state)
|
||||
if not buflen then return nil, msg end
|
||||
prev = true -- add a seperator before the next element
|
||||
end
|
||||
end
|
||||
else -- unordered
|
||||
for k,v in pairs (value) do
|
||||
buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder, state)
|
||||
if not buflen then return nil, msg end
|
||||
prev = true -- add a seperator before the next element
|
||||
end
|
||||
end
|
||||
if indent then
|
||||
buflen = addnewline2 (level - 1, buffer, buflen)
|
||||
end
|
||||
buflen = buflen + 1
|
||||
buffer[buflen] = "}"
|
||||
end
|
||||
tables[value] = nil
|
||||
else
|
||||
return exception ('unsupported type', value, state, buffer, buflen,
|
||||
"type '" .. valtype .. "' is not supported by JSON.")
|
||||
end
|
||||
return buflen
|
||||
end
|
||||
|
||||
function json.encode (value, state)
|
||||
state = state or {}
|
||||
local oldbuffer = state.buffer
|
||||
local buffer = oldbuffer or {}
|
||||
state.buffer = buffer
|
||||
updatedecpoint()
|
||||
local ret, msg = encode2 (value, state.indent, state.level or 0,
|
||||
buffer, state.bufferlen or 0, state.tables or {}, state.keyorder, state)
|
||||
if not ret then
|
||||
error (msg, 2)
|
||||
elseif oldbuffer == buffer then
|
||||
state.bufferlen = ret
|
||||
return true
|
||||
else
|
||||
state.bufferlen = nil
|
||||
state.buffer = nil
|
||||
return concat (buffer)
|
||||
end
|
||||
end
|
||||
|
||||
local function loc (str, where)
|
||||
local line, pos, linepos = 1, 1, 0
|
||||
while true do
|
||||
pos = strfind (str, "\n", pos, true)
|
||||
if pos and pos < where then
|
||||
line = line + 1
|
||||
linepos = pos
|
||||
pos = pos + 1
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
return "line " .. line .. ", column " .. (where - linepos)
|
||||
end
|
||||
|
||||
local function unterminated (str, what, where)
|
||||
return nil, strlen (str) + 1, "unterminated " .. what .. " at " .. loc (str, where)
|
||||
end
|
||||
|
||||
local function scanwhite (str, pos)
|
||||
while true do
|
||||
pos = strfind (str, "%S", pos)
|
||||
if not pos then return nil end
|
||||
local sub2 = strsub (str, pos, pos + 1)
|
||||
if sub2 == "\239\187" and strsub (str, pos + 2, pos + 2) == "\191" then
|
||||
-- UTF-8 Byte Order Mark
|
||||
pos = pos + 3
|
||||
elseif sub2 == "//" then
|
||||
pos = strfind (str, "[\n\r]", pos + 2)
|
||||
if not pos then return nil end
|
||||
elseif sub2 == "/*" then
|
||||
pos = strfind (str, "*/", pos + 2)
|
||||
if not pos then return nil end
|
||||
pos = pos + 2
|
||||
else
|
||||
return pos
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local escapechars = {
|
||||
["\""] = "\"", ["\\"] = "\\", ["/"] = "/", ["b"] = "\b", ["f"] = "\f",
|
||||
["n"] = "\n", ["r"] = "\r", ["t"] = "\t"
|
||||
}
|
||||
|
||||
local function unichar (value)
|
||||
if value < 0 then
|
||||
return nil
|
||||
elseif value <= 0x007f then
|
||||
return strchar (value)
|
||||
elseif value <= 0x07ff then
|
||||
return strchar (0xc0 + floor(value/0x40),
|
||||
0x80 + (floor(value) % 0x40))
|
||||
elseif value <= 0xffff then
|
||||
return strchar (0xe0 + floor(value/0x1000),
|
||||
0x80 + (floor(value/0x40) % 0x40),
|
||||
0x80 + (floor(value) % 0x40))
|
||||
elseif value <= 0x10ffff then
|
||||
return strchar (0xf0 + floor(value/0x40000),
|
||||
0x80 + (floor(value/0x1000) % 0x40),
|
||||
0x80 + (floor(value/0x40) % 0x40),
|
||||
0x80 + (floor(value) % 0x40))
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
local function scanstring (str, pos)
|
||||
local lastpos = pos + 1
|
||||
local buffer, n = {}, 0
|
||||
while true do
|
||||
local nextpos = strfind (str, "[\"\\]", lastpos)
|
||||
if not nextpos then
|
||||
return unterminated (str, "string", pos)
|
||||
end
|
||||
if nextpos > lastpos then
|
||||
n = n + 1
|
||||
buffer[n] = strsub (str, lastpos, nextpos - 1)
|
||||
end
|
||||
if strsub (str, nextpos, nextpos) == "\"" then
|
||||
lastpos = nextpos + 1
|
||||
break
|
||||
else
|
||||
local escchar = strsub (str, nextpos + 1, nextpos + 1)
|
||||
local value
|
||||
if escchar == "u" then
|
||||
value = tonumber (strsub (str, nextpos + 2, nextpos + 5), 16)
|
||||
if value then
|
||||
local value2
|
||||
if 0xD800 <= value and value <= 0xDBff then
|
||||
-- we have the high surrogate of UTF-16. Check if there is a
|
||||
-- low surrogate escaped nearby to combine them.
|
||||
if strsub (str, nextpos + 6, nextpos + 7) == "\\u" then
|
||||
value2 = tonumber (strsub (str, nextpos + 8, nextpos + 11), 16)
|
||||
if value2 and 0xDC00 <= value2 and value2 <= 0xDFFF then
|
||||
value = (value - 0xD800) * 0x400 + (value2 - 0xDC00) + 0x10000
|
||||
else
|
||||
value2 = nil -- in case it was out of range for a low surrogate
|
||||
end
|
||||
end
|
||||
end
|
||||
value = value and unichar (value)
|
||||
if value then
|
||||
if value2 then
|
||||
lastpos = nextpos + 12
|
||||
else
|
||||
lastpos = nextpos + 6
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if not value then
|
||||
value = escapechars[escchar] or escchar
|
||||
lastpos = nextpos + 2
|
||||
end
|
||||
n = n + 1
|
||||
buffer[n] = value
|
||||
end
|
||||
end
|
||||
if n == 1 then
|
||||
return buffer[1], lastpos
|
||||
elseif n > 1 then
|
||||
return concat (buffer), lastpos
|
||||
else
|
||||
return "", lastpos
|
||||
end
|
||||
end
|
||||
|
||||
local scanvalue -- forward declaration
|
||||
|
||||
local function scantable (what, closechar, str, startpos, nullval, objectmeta, arraymeta)
|
||||
local len = strlen (str)
|
||||
local tbl, n = {}, 0
|
||||
local pos = startpos + 1
|
||||
if what == 'object' then
|
||||
setmetatable (tbl, objectmeta)
|
||||
else
|
||||
setmetatable (tbl, arraymeta)
|
||||
end
|
||||
while true do
|
||||
pos = scanwhite (str, pos)
|
||||
if not pos then return unterminated (str, what, startpos) end
|
||||
local char = strsub (str, pos, pos)
|
||||
if char == closechar then
|
||||
return tbl, pos + 1
|
||||
end
|
||||
local val1, err
|
||||
val1, pos, err = scanvalue (str, pos, nullval, objectmeta, arraymeta)
|
||||
if err then return nil, pos, err end
|
||||
pos = scanwhite (str, pos)
|
||||
if not pos then return unterminated (str, what, startpos) end
|
||||
char = strsub (str, pos, pos)
|
||||
if char == ":" then
|
||||
if val1 == nil then
|
||||
return nil, pos, "cannot use nil as table index (at " .. loc (str, pos) .. ")"
|
||||
end
|
||||
pos = scanwhite (str, pos + 1)
|
||||
if not pos then return unterminated (str, what, startpos) end
|
||||
local val2
|
||||
val2, pos, err = scanvalue (str, pos, nullval, objectmeta, arraymeta)
|
||||
if err then return nil, pos, err end
|
||||
tbl[val1] = val2
|
||||
pos = scanwhite (str, pos)
|
||||
if not pos then return unterminated (str, what, startpos) end
|
||||
char = strsub (str, pos, pos)
|
||||
else
|
||||
n = n + 1
|
||||
tbl[n] = val1
|
||||
end
|
||||
if char == "," then
|
||||
pos = pos + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
scanvalue = function (str, pos, nullval, objectmeta, arraymeta)
|
||||
pos = pos or 1
|
||||
pos = scanwhite (str, pos)
|
||||
if not pos then
|
||||
return nil, strlen (str) + 1, "no valid JSON value (reached the end)"
|
||||
end
|
||||
local char = strsub (str, pos, pos)
|
||||
if char == "{" then
|
||||
return scantable ('object', "}", str, pos, nullval, objectmeta, arraymeta)
|
||||
elseif char == "[" then
|
||||
return scantable ('array', "]", str, pos, nullval, objectmeta, arraymeta)
|
||||
elseif char == "\"" then
|
||||
return scanstring (str, pos)
|
||||
else
|
||||
local pstart, pend = strfind (str, "^%-?[%d%.]+[eE]?[%+%-]?%d*", pos)
|
||||
if pstart then
|
||||
local number = str2num (strsub (str, pstart, pend))
|
||||
if number then
|
||||
return number, pend + 1
|
||||
end
|
||||
end
|
||||
pstart, pend = strfind (str, "^%a%w*", pos)
|
||||
if pstart then
|
||||
local name = strsub (str, pstart, pend)
|
||||
if name == "true" then
|
||||
return true, pend + 1
|
||||
elseif name == "false" then
|
||||
return false, pend + 1
|
||||
elseif name == "null" then
|
||||
return nullval, pend + 1
|
||||
end
|
||||
end
|
||||
return nil, pos, "no valid JSON value at " .. loc (str, pos)
|
||||
end
|
||||
end
|
||||
|
||||
local function optionalmetatables(...)
|
||||
if select("#", ...) > 0 then
|
||||
return ...
|
||||
else
|
||||
return {__jsontype = 'object'}, {__jsontype = 'array'}
|
||||
end
|
||||
end
|
||||
|
||||
function json.decode (str, pos, nullval, ...)
|
||||
local objectmeta, arraymeta = optionalmetatables(...)
|
||||
return scanvalue (str, pos, nullval, objectmeta, arraymeta)
|
||||
end
|
||||
|
||||
function json.use_lpeg ()
|
||||
local g = require ("lpeg")
|
||||
|
||||
if g.version() == "0.11" then
|
||||
error "due to a bug in LPeg 0.11, it cannot be used for JSON matching"
|
||||
end
|
||||
|
||||
local pegmatch = g.match
|
||||
local P, S, R = g.P, g.S, g.R
|
||||
|
||||
local function ErrorCall (str, pos, msg, state)
|
||||
if not state.msg then
|
||||
state.msg = msg .. " at " .. loc (str, pos)
|
||||
state.pos = pos
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function Err (msg)
|
||||
return g.Cmt (g.Cc (msg) * g.Carg (2), ErrorCall)
|
||||
end
|
||||
|
||||
local SingleLineComment = P"//" * (1 - S"\n\r")^0
|
||||
local MultiLineComment = P"/*" * (1 - P"*/")^0 * P"*/"
|
||||
local Space = (S" \n\r\t" + P"\239\187\191" + SingleLineComment + MultiLineComment)^0
|
||||
|
||||
local PlainChar = 1 - S"\"\\\n\r"
|
||||
local EscapeSequence = (P"\\" * g.C (S"\"\\/bfnrt" + Err "unsupported escape sequence")) / escapechars
|
||||
local HexDigit = R("09", "af", "AF")
|
||||
local function UTF16Surrogate (match, pos, high, low)
|
||||
high, low = tonumber (high, 16), tonumber (low, 16)
|
||||
if 0xD800 <= high and high <= 0xDBff and 0xDC00 <= low and low <= 0xDFFF then
|
||||
return true, unichar ((high - 0xD800) * 0x400 + (low - 0xDC00) + 0x10000)
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
local function UTF16BMP (hex)
|
||||
return unichar (tonumber (hex, 16))
|
||||
end
|
||||
local U16Sequence = (P"\\u" * g.C (HexDigit * HexDigit * HexDigit * HexDigit))
|
||||
local UnicodeEscape = g.Cmt (U16Sequence * U16Sequence, UTF16Surrogate) + U16Sequence/UTF16BMP
|
||||
local Char = UnicodeEscape + EscapeSequence + PlainChar
|
||||
local String = P"\"" * g.Cs (Char ^ 0) * (P"\"" + Err "unterminated string")
|
||||
local Integer = P"-"^(-1) * (P"0" + (R"19" * R"09"^0))
|
||||
local Fractal = P"." * R"09"^0
|
||||
local Exponent = (S"eE") * (S"+-")^(-1) * R"09"^1
|
||||
local Number = (Integer * Fractal^(-1) * Exponent^(-1))/str2num
|
||||
local Constant = P"true" * g.Cc (true) + P"false" * g.Cc (false) + P"null" * g.Carg (1)
|
||||
local SimpleValue = Number + String + Constant
|
||||
local ArrayContent, ObjectContent
|
||||
|
||||
-- The functions parsearray and parseobject parse only a single value/pair
|
||||
-- at a time and store them directly to avoid hitting the LPeg limits.
|
||||
local function parsearray (str, pos, nullval, state)
|
||||
local obj, cont
|
||||
local npos
|
||||
local t, nt = {}, 0
|
||||
repeat
|
||||
obj, cont, npos = pegmatch (ArrayContent, str, pos, nullval, state)
|
||||
if not npos then break end
|
||||
pos = npos
|
||||
nt = nt + 1
|
||||
t[nt] = obj
|
||||
until cont == 'last'
|
||||
return pos, setmetatable (t, state.arraymeta)
|
||||
end
|
||||
|
||||
local function parseobject (str, pos, nullval, state)
|
||||
local obj, key, cont
|
||||
local npos
|
||||
local t = {}
|
||||
repeat
|
||||
key, obj, cont, npos = pegmatch (ObjectContent, str, pos, nullval, state)
|
||||
if not npos then break end
|
||||
pos = npos
|
||||
t[key] = obj
|
||||
until cont == 'last'
|
||||
return pos, setmetatable (t, state.objectmeta)
|
||||
end
|
||||
|
||||
local Array = P"[" * g.Cmt (g.Carg(1) * g.Carg(2), parsearray) * Space * (P"]" + Err "']' expected")
|
||||
local Object = P"{" * g.Cmt (g.Carg(1) * g.Carg(2), parseobject) * Space * (P"}" + Err "'}' expected")
|
||||
local Value = Space * (Array + Object + SimpleValue)
|
||||
local ExpectedValue = Value + Space * Err "value expected"
|
||||
ArrayContent = Value * Space * (P"," * g.Cc'cont' + g.Cc'last') * g.Cp()
|
||||
local Pair = g.Cg (Space * String * Space * (P":" + Err "colon expected") * ExpectedValue)
|
||||
ObjectContent = Pair * Space * (P"," * g.Cc'cont' + g.Cc'last') * g.Cp()
|
||||
local DecodeValue = ExpectedValue * g.Cp ()
|
||||
|
||||
function json.decode (str, pos, nullval, ...)
|
||||
local state = {}
|
||||
state.objectmeta, state.arraymeta = optionalmetatables(...)
|
||||
local obj, retpos = pegmatch (DecodeValue, str, pos, nullval, state)
|
||||
if state.msg then
|
||||
return nil, state.pos, state.msg
|
||||
else
|
||||
return obj, retpos
|
||||
end
|
||||
end
|
||||
|
||||
-- use this function only once:
|
||||
json.use_lpeg = function () return json end
|
||||
|
||||
json.using_lpeg = true
|
||||
|
||||
return json -- so you can get the module using json = require "dkjson".use_lpeg()
|
||||
end
|
||||
|
||||
if always_try_using_lpeg then
|
||||
pcall (json.use_lpeg)
|
||||
end
|
||||
|
||||
return json
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
#Ship types
|
||||
#Ship types
|
||||
|
||||
$Name: Navbuoy
|
||||
$Max Debris Speed: 200
|
||||
$FF Multiplier: 1.0
|
||||
@@ -12,6 +12,7 @@ $AI:
|
||||
+Turrets attack this: YES
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Vaporize Percent Chance: 0.0
|
||||
|
||||
$Name: Sentry Gun
|
||||
$Counts for Alone: YES
|
||||
$On Hotkey List: YES
|
||||
@@ -32,6 +33,7 @@ $AI:
|
||||
+Turrets attack this: YES
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Vaporize Percent Chance: 0.0
|
||||
|
||||
$Name: Escape Pod
|
||||
$Praise Destruction: YES
|
||||
$On Hotkey List: YES
|
||||
@@ -50,6 +52,7 @@ $AI:
|
||||
+Turrets attack this: YES
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Vaporize Percent Chance: 0.0
|
||||
|
||||
$Name: Cargo
|
||||
$Scannable: YES
|
||||
$Max Debris Speed: 200
|
||||
@@ -63,6 +66,7 @@ $Fog:
|
||||
$AI:
|
||||
+Passive docks: ( "cargo" )
|
||||
$Vaporize Percent Chance: 0.0
|
||||
|
||||
$Name: Support
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -89,6 +93,7 @@ $AI:
|
||||
+Active docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Vaporize Percent Chance: 0.0
|
||||
|
||||
;;WMC - Stealth ships always have another type, so this isn't used
|
||||
$Name: Stealth
|
||||
$Counts for Alone: YES
|
||||
@@ -114,6 +119,7 @@ $AI:
|
||||
+Passive docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Vaporize Percent Chance: 0.0
|
||||
|
||||
$Name: Fighter
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -141,6 +147,7 @@ $AI:
|
||||
+Passive docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Vaporize Percent Chance: 0.0
|
||||
|
||||
$Name: Bomber
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -168,7 +175,8 @@ $AI:
|
||||
+Passive docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Vaporize Percent Chance: 0.0
|
||||
;;WMC - This fighter/bomber type doesn't seem to be used anywhere, because no ship is set as both fighter and bomber
|
||||
|
||||
;;WMC - This fighter/bomber type doesn't seem to be used anywhere, because no ship is set as both fighter and bomber
|
||||
$Name: Fighter/bomber
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -195,6 +203,7 @@ $AI:
|
||||
+Passive docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Vaporize Percent Chance: 0.0
|
||||
|
||||
$Name: Transport
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -204,6 +213,7 @@ $Show Attack Direction: YES
|
||||
$Max Debris Speed: 150
|
||||
$FF Multiplier: 1.0
|
||||
$EMP Multiplier: 2.0
|
||||
$Warp Sound Range Multiplier: 6.0
|
||||
$Beams Easily Hit: YES
|
||||
$Protected on cripple: YES
|
||||
$Fog:
|
||||
@@ -223,6 +233,7 @@ $AI:
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Vaporize Percent Chance: 0.0
|
||||
|
||||
$Name: Freighter
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -233,6 +244,7 @@ $Scannable: YES
|
||||
$Max Debris Speed: 150
|
||||
$FF Multiplier: 1.0
|
||||
$EMP Multiplier: 1.75
|
||||
$Warp Sound Range Multiplier: 6.0
|
||||
$Beams Easily Hit: YES
|
||||
$Protected on cripple: YES
|
||||
$Fog:
|
||||
@@ -253,6 +265,7 @@ $AI:
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Vaporize Percent Chance: 0.0
|
||||
|
||||
$Name: AWACS
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -262,6 +275,7 @@ $Show Attack Direction: YES
|
||||
$Max Debris Speed: 150
|
||||
$FF Multiplier: 1.0
|
||||
$EMP Multiplier: 0.8
|
||||
$Warp Sound Range Multiplier: 6.0
|
||||
$Beams Easily Hit: YES
|
||||
$Protected on cripple: YES
|
||||
$Fog:
|
||||
@@ -281,6 +295,7 @@ $AI:
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Vaporize Percent Chance: 0.0
|
||||
|
||||
$Name: Gas Miner
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -290,6 +305,7 @@ $Show Attack Direction: YES
|
||||
$Max Debris Speed: 150
|
||||
$FF Multiplier: 1.0
|
||||
$EMP Multiplier: 1.0
|
||||
$Warp Sound Range Multiplier: 6.0
|
||||
$Beams Easily Hit: YES
|
||||
$Protected on cripple: YES
|
||||
$Fog:
|
||||
@@ -309,6 +325,7 @@ $AI:
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Vaporize Percent Chance: 0.0
|
||||
|
||||
$Name: Cruiser
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -318,6 +335,7 @@ $Show Attack Direction: YES
|
||||
$Max Debris Speed: 150
|
||||
$FF Multiplier: 1.0
|
||||
$EMP Multiplier: 0.9
|
||||
$Warp Sound Range Multiplier: 6.0
|
||||
$Beams Easily Hit: YES
|
||||
$Protected on cripple: YES
|
||||
$Fog:
|
||||
@@ -337,6 +355,7 @@ $AI:
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Vaporize Percent Chance: 0.0
|
||||
|
||||
$Name: Corvette
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -346,6 +365,7 @@ $Show Attack Direction: YES
|
||||
$Max Debris Speed: 150
|
||||
$FF Multiplier: 1.0
|
||||
$EMP Multiplier: 0.3333
|
||||
$Warp Sound Range Multiplier: 6.0
|
||||
$Beams Easily Hit: YES
|
||||
$Protected on cripple: YES
|
||||
$Fog:
|
||||
@@ -365,6 +385,7 @@ $AI:
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Vaporize Percent Chance: 0.0
|
||||
|
||||
$Name: Capital
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -394,6 +415,7 @@ $AI:
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Vaporize Percent Chance: 0.0
|
||||
|
||||
$Name: Super Cap
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -421,6 +443,7 @@ $AI:
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Vaporize Percent Chance: 0.0
|
||||
|
||||
$Name: Drydock
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -446,6 +469,7 @@ $AI:
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Vaporize Percent Chance: 0.0
|
||||
|
||||
$Name: Knossos Device
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
@@ -469,4 +493,5 @@ $AI:
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Vaporize Percent Chance: 0.0
|
||||
#End
|
||||
|
||||
#End
|
||||
@@ -311,7 +311,7 @@ static char* GetFilePart(char *source)
|
||||
SCP_string safe_string;
|
||||
|
||||
// Entry point into the main exception handling routine. This routine is put into an except()
|
||||
// statment at the beginning of a thread and is called anytime that there is a program exception
|
||||
// statement at the beginning of a thread and is called anytime that there is a program exception
|
||||
// The data is stored in a file called ErrorLog.txt in the data directory.
|
||||
//
|
||||
// data: pointer to the exception data
|
||||
|
||||
+36
-29
@@ -48,44 +48,51 @@ bool fireballs_parsed = false;
|
||||
|
||||
bool Fireball_use_3d_warp = false;
|
||||
|
||||
static auto WarpOption __UNUSED = options::OptionBuilder<bool>("Graphics.3dWarp", "3D Warp", "Use a 3D model for warp effects")
|
||||
.category("Graphics")
|
||||
.default_val(true)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.bind_to(&Fireball_use_3d_warp)
|
||||
.importance(65)
|
||||
.finish();
|
||||
static auto WarpOption __UNUSED = options::OptionBuilder<bool>("Graphics.3dWarp",
|
||||
std::pair<const char*, int>{"3D Warp", 1770},
|
||||
std::pair<const char*, int>{"Use a 3D model for warp effects", 1771})
|
||||
.category("Graphics")
|
||||
.default_val(true)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.bind_to(&Fireball_use_3d_warp)
|
||||
.importance(65)
|
||||
.finish();
|
||||
|
||||
/**
|
||||
* Play warp in sound for warp effect
|
||||
*/
|
||||
void fireball_play_warphole_open_sound(int ship_class, fireball *fb)
|
||||
{
|
||||
gamesnd_id sound_index;
|
||||
float range_multiplier = 1.0f;
|
||||
object *fireball_objp;
|
||||
|
||||
Assert((fb != NULL) && (fb->objnum >= 0));
|
||||
if((fb == NULL) || (fb->objnum < 0)){
|
||||
return;
|
||||
}
|
||||
fireball_objp = &Objects[fb->objnum];
|
||||
auto fireball_objp = &Objects[fb->objnum];
|
||||
auto sound_index = gamesnd_id(GameSounds::WARP_IN);
|
||||
|
||||
sound_index = gamesnd_id(GameSounds::WARP_IN);
|
||||
|
||||
if(fb->warp_open_sound_index.isValid()) {
|
||||
if (fb->warp_open_sound_index.isValid()) {
|
||||
sound_index = fb->warp_open_sound_index;
|
||||
} else if ((ship_class >= 0) && (ship_class < ship_info_size())) {
|
||||
if ( Ship_info[ship_class].is_huge_ship() ) {
|
||||
sound_index = gamesnd_id(GameSounds::CAPITAL_WARP_IN);
|
||||
fb->flags |= FBF_WARP_CAPITAL_SIZE;
|
||||
} else if ( Ship_info[ship_class].is_big_ship() ) {
|
||||
range_multiplier = 6.0f;
|
||||
fb->flags |= FBF_WARP_CRUISER_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
snd_play_3d(gamesnd_get_game_sound(sound_index), &fireball_objp->pos, &Eye_position, fireball_objp->radius, NULL, 0, 1.0f, SND_PRIORITY_DOUBLE_INSTANCE, NULL, range_multiplier); // play warp sound effect
|
||||
if (ship_class >= 0 && ship_class < ship_info_size()) {
|
||||
if (Ship_info[ship_class].is_huge_ship()) {
|
||||
fb->flags |= FBF_WARP_CAPITAL_SIZE;
|
||||
} else if (Ship_info[ship_class].is_big_ship()) {
|
||||
fb->flags |= FBF_WARP_CRUISER_SIZE;
|
||||
}
|
||||
|
||||
// originally 6.0 for SIF_BIG_SHIP and 1.0 for everything else
|
||||
if (Ship_info[ship_class].class_type >= 0)
|
||||
fb->warp_sound_range_multiplier = Ship_types[Ship_info[ship_class].class_type].warp_sound_range_multiplier;
|
||||
else
|
||||
fb->warp_sound_range_multiplier = 1.0f;
|
||||
}
|
||||
|
||||
snd_play_3d(gamesnd_get_game_sound(sound_index), &fireball_objp->pos, &Eye_position, fireball_objp->radius, NULL, 0, 1.0f, SND_PRIORITY_DOUBLE_INSTANCE, NULL, fb->warp_sound_range_multiplier); // play warp sound effect
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -93,15 +100,14 @@ void fireball_play_warphole_open_sound(int ship_class, fireball *fb)
|
||||
*/
|
||||
void fireball_play_warphole_close_sound(fireball *fb)
|
||||
{
|
||||
gamesnd_id sound_index;
|
||||
Assert((fb != NULL) && (fb->objnum >= 0));
|
||||
if((fb == NULL) || (fb->objnum < 0)){
|
||||
return;
|
||||
}
|
||||
auto fireball_objp = &Objects[fb->objnum];
|
||||
auto sound_index = gamesnd_id(GameSounds::WARP_OUT);
|
||||
|
||||
object *fireball_objp;
|
||||
|
||||
fireball_objp = &Objects[fb->objnum];
|
||||
|
||||
sound_index = gamesnd_id(GameSounds::WARP_OUT);
|
||||
|
||||
if ( fb->warp_close_sound_index.isValid() ) {
|
||||
if (fb->warp_close_sound_index.isValid()) {
|
||||
sound_index = fb->warp_close_sound_index;
|
||||
} else if ( fb->flags & FBF_WARP_CAPITAL_SIZE ) {
|
||||
sound_index = gamesnd_id(GameSounds::CAPITAL_WARP_OUT);
|
||||
@@ -109,7 +115,7 @@ void fireball_play_warphole_close_sound(fireball *fb)
|
||||
return;
|
||||
}
|
||||
|
||||
snd_play_3d(gamesnd_get_game_sound(sound_index), &fireball_objp->pos, &Eye_position, fireball_objp->radius); // play warp sound effect
|
||||
snd_play_3d(gamesnd_get_game_sound(sound_index), &fireball_objp->pos, &Eye_position, fireball_objp->radius, NULL, 0, 1.0F, SND_PRIORITY_SINGLE_INSTANCE, NULL, fb->warp_sound_range_multiplier); // play warp sound effect
|
||||
}
|
||||
|
||||
static void fireball_generate_unique_id(char *unique_id, int buffer_len, int fireball_index)
|
||||
@@ -845,6 +851,7 @@ int fireball_create(vec3d *pos, int fireball_type, int render_type, int parent_o
|
||||
new_fireball->warp_close_sound_index = warp_close_sound;
|
||||
new_fireball->warp_open_duration = (warp_open_duration < 0.0f) ? WARPHOLE_GROW_TIME : warp_open_duration;
|
||||
new_fireball->warp_close_duration = (warp_close_duration < 0.0f) ? WARPHOLE_GROW_TIME : warp_close_duration;
|
||||
new_fireball->warp_sound_range_multiplier = 1.0f;
|
||||
|
||||
matrix orient;
|
||||
if(orient_override != NULL){
|
||||
|
||||
@@ -40,8 +40,6 @@ class asteroid_info;
|
||||
|
||||
#define FIREBALL_NUM_LARGE_EXPLOSIONS 2
|
||||
|
||||
#define MAX_FIREBALLS 200
|
||||
|
||||
extern int fireball_used[MAX_FIREBALL_TYPES];
|
||||
|
||||
// all this moved here by Goober5000 because it makes more sense in the H file
|
||||
@@ -94,6 +92,9 @@ typedef struct fireball {
|
||||
gamesnd_id warp_close_sound_index;
|
||||
float warp_open_duration;
|
||||
float warp_close_duration;
|
||||
|
||||
// the sound multiplier is based on the ship class, but we lose that while the warp is closing
|
||||
float warp_sound_range_multiplier;
|
||||
} fireball;
|
||||
// end move
|
||||
|
||||
|
||||
@@ -24,13 +24,15 @@
|
||||
|
||||
bool Fireball_warp_flash = false;
|
||||
|
||||
static auto WarpFlashOption __UNUSED = options::OptionBuilder<bool>("Graphics.WarpFlash", "Warp Flash", "Show flash upon warp open or close")
|
||||
.category("Graphics")
|
||||
.default_val(true)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.bind_to_once(&Fireball_warp_flash)
|
||||
.importance(65)
|
||||
.finish();
|
||||
static auto WarpFlashOption __UNUSED = options::OptionBuilder<bool>("Graphics.WarpFlash",
|
||||
std::pair<const char*, int>{"Warp Flash", 1768},
|
||||
std::pair<const char*, int>{"Show flash upon warp open or close", 1769})
|
||||
.category("Graphics")
|
||||
.default_val(true)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.bind_to_once(&Fireball_warp_flash)
|
||||
.importance(65)
|
||||
.finish();
|
||||
|
||||
void warpin_batch_draw_face( int texture, vertex *v1, vertex *v2, vertex *v3 )
|
||||
{
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "gamesnd/gamesnd.h"
|
||||
#include "globalincs/alphacolors.h"
|
||||
#include "io/key.h"
|
||||
#include "mission/missionmessage.h"
|
||||
#include "missionui/missionscreencommon.h"
|
||||
#include "sound/audiostr.h"
|
||||
#include "ui/ui.h"
|
||||
@@ -516,8 +517,7 @@ void gameplay_help_leave()
|
||||
// unpause all game sounds
|
||||
weapon_unpause_sounds();
|
||||
audiostream_unpause_all();
|
||||
|
||||
Help_text.clear();
|
||||
message_resume_all();
|
||||
|
||||
gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
|
||||
game_flush();
|
||||
@@ -633,6 +633,7 @@ void gameplay_help_do_frame(float /*frametime*/)
|
||||
// make sure game sounds are paused
|
||||
weapon_pause_sounds();
|
||||
audiostream_pause_all();
|
||||
message_pause_all();
|
||||
|
||||
k = Ui_window.process() & ~KEY_DEBUGGED;
|
||||
gameplay_help_process_key(k);
|
||||
|
||||
+94
-44
@@ -45,13 +45,15 @@ static bool music_volume_change_listener(float new_val, bool /*initial*/)
|
||||
return true;
|
||||
}
|
||||
|
||||
static auto MusicVolumeOption __UNUSED = options::OptionBuilder<float>("Audio.Music", "Music", "Volume used for playing music")
|
||||
.category("Audio")
|
||||
.default_val(Default_music_volume)
|
||||
.range(0.0f, 1.0f)
|
||||
.change_listener(music_volume_change_listener)
|
||||
.importance(1)
|
||||
.finish();
|
||||
static auto MusicVolumeOption __UNUSED = options::OptionBuilder<float>("Audio.Music",
|
||||
std::pair<const char*, int>{"Music", 1371},
|
||||
std::pair<const char*, int>{"Volume used for playing music", 1760})
|
||||
.category("Audio")
|
||||
.default_val(Default_music_volume)
|
||||
.range(0.0f, 1.0f)
|
||||
.change_listener(music_volume_change_listener)
|
||||
.importance(1)
|
||||
.finish();
|
||||
|
||||
typedef struct tagSNDPATTERN {
|
||||
int default_next_pattern; // Needed so the next_pattern member can be reset
|
||||
@@ -257,6 +259,19 @@ SCP_vector<menu_music> Spooled_music;
|
||||
int Mission_music[NUM_SCORES];
|
||||
|
||||
|
||||
bool event_music_pattern_is_skippable(const SOUNDTRACK_PATTERN_INFO &pattern)
|
||||
{
|
||||
// check for blank or "none"
|
||||
if (pattern.fname[0] == '\0' || !strnicmp(pattern.fname, NOX("none.wav"), 4))
|
||||
return true;
|
||||
|
||||
// no content means this pattern isn't intended to play
|
||||
if (pattern.num_measures == 0 || pattern.samples_per_measure == 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// event_music_init()
|
||||
//
|
||||
@@ -289,6 +304,51 @@ void event_music_init()
|
||||
|
||||
// look for any modular tables
|
||||
parse_modular_table(NOX("*-mus.tbm"), event_music_parse_musictbl);
|
||||
|
||||
|
||||
// now that we've parsed everything, check the validity
|
||||
for (auto &soundtrack : Soundtracks)
|
||||
{
|
||||
bool all_patterns_valid = true;
|
||||
|
||||
// Goober5000 - set the valid flag according to whether we can load all our patterns
|
||||
// (since someone may be running an enhanced music.tbl without warble_fs1 installed)
|
||||
for (int i = 0; i < soundtrack.num_patterns; i++)
|
||||
{
|
||||
auto filename = soundtrack.patterns[i].fname;
|
||||
|
||||
// some patterns aren't played for various legitimate reasons
|
||||
if (event_music_pattern_is_skippable(soundtrack.patterns[i]))
|
||||
continue;
|
||||
|
||||
// check for negative numbers (zero is allowed)
|
||||
if (soundtrack.patterns[i].num_measures < 0 || soundtrack.patterns[i].samples_per_measure < 0)
|
||||
{
|
||||
Warning(LOCATION, "Soundtrack file %s has a negative 'num_measures' or 'samples_per_measure'; this is not allowed", soundtrack.patterns[i].fname);
|
||||
all_patterns_valid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// check for file with exact extension
|
||||
// (since event music specifies samples and measures, the audio format is important; so we don't want to assume any format will work)
|
||||
if (!cf_exists_full(filename, CF_TYPE_MUSIC))
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
// see if the file exists with a different extension
|
||||
auto res = cf_find_file_location_ext(filename, NUM_AUDIO_EXT, audio_ext_list, CF_TYPE_MUSIC);
|
||||
if (res.found)
|
||||
Warning(LOCATION, "Soundtrack file %s was not found with its specified extension, but another file %s exists in the modpack. Please update the extension and adjust audio specifications if necessary.", filename, res.name_ext.c_str());
|
||||
#endif
|
||||
|
||||
Warning(LOCATION, "One or more files in '%s' could not be loaded. The soundtrack will not be used.", soundtrack.name);
|
||||
all_patterns_valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (all_patterns_valid)
|
||||
soundtrack.flags |= EMF_VALID;
|
||||
}
|
||||
|
||||
Event_music_inited = TRUE;
|
||||
Event_music_begun = FALSE;
|
||||
@@ -410,7 +470,7 @@ void event_music_do_frame()
|
||||
|
||||
// start off the music delayed
|
||||
if ( timestamp_elapsed(Pattern_timer_id) ) {
|
||||
Pattern_timer_id = TIMESTAMP::invalid();
|
||||
Pattern_timer_id = TIMESTAMP::never();
|
||||
Event_music_begun = TRUE;
|
||||
if ( Current_pattern != -1 && Patterns[Current_pattern].handle >= 0) {
|
||||
//WMC - removed in favor of if
|
||||
@@ -544,14 +604,14 @@ void event_music_level_start(int force_soundtrack)
|
||||
if (force_soundtrack != -1)
|
||||
Current_soundtrack_num = force_soundtrack;
|
||||
|
||||
// Check that soundtrack index is in range, except that < 0 means no soundtrack
|
||||
if (Current_soundtrack_num < 0)
|
||||
{
|
||||
Pattern_timer_id = TIMESTAMP::never(); // update the timestamp as if a soundtrack did start
|
||||
return;
|
||||
}
|
||||
|
||||
Assert(Current_soundtrack_num >= 0 && Current_soundtrack_num < (int)Soundtracks.size());
|
||||
|
||||
if (Current_soundtrack_num < 0 || Current_soundtrack_num > (int)Soundtracks.size())
|
||||
Assert(Current_soundtrack_num < (int)Soundtracks.size());
|
||||
if (Current_soundtrack_num >= (int)Soundtracks.size())
|
||||
return;
|
||||
|
||||
strack = &Soundtracks[Current_soundtrack_num];
|
||||
@@ -564,7 +624,7 @@ void event_music_level_start(int force_soundtrack)
|
||||
// tracks because their patterns weren't -1
|
||||
for (i = 0; i < MAX_PATTERNS; i++)
|
||||
{
|
||||
if (!strnicmp(strack->patterns[i].fname, NOX("none.wav"), 4))
|
||||
if (event_music_pattern_is_skippable(strack->patterns[i]))
|
||||
{
|
||||
Patterns[i].handle = -1;
|
||||
continue;
|
||||
@@ -644,7 +704,9 @@ void event_music_first_pattern()
|
||||
// if we really are initializing the level
|
||||
if (Missiontime == 0) {
|
||||
Pattern_timer_id = TIMESTAMP::invalid(); // don't let this start quite yet; see event_music_set_start_delay()
|
||||
} else {
|
||||
}
|
||||
// don't step on a timestamp in progress; only set it if it has elapsed at least once already
|
||||
else if (Pattern_timer_id.isNever()) {
|
||||
Pattern_timer_id = TIMESTAMP::immediate(); // start immediately
|
||||
}
|
||||
|
||||
@@ -1166,9 +1228,6 @@ void parse_soundtrack()
|
||||
int i, strack_idx = -1;
|
||||
bool nocreate = false;
|
||||
|
||||
//Start parsing soundtrack
|
||||
//required_string("#Soundtrack Start");
|
||||
|
||||
//Get the name, and do we have this track already?
|
||||
required_string("$SoundTrack Name:");
|
||||
stuff_string(namebuf, F_NAME, NAME_LENGTH);
|
||||
@@ -1284,23 +1343,6 @@ void parse_soundtrack()
|
||||
|
||||
//We're done here.
|
||||
required_string("#SoundTrack End");
|
||||
|
||||
|
||||
// Goober5000 - set the valid flag according to whether we can load all our patterns
|
||||
// (since someone may be running an enhanced music.tbl without warble_fs1 installed)
|
||||
for (i = 0; i < Soundtracks[strack_idx].num_patterns; i++)
|
||||
{
|
||||
// check for "none"
|
||||
if (!strlen(Soundtracks[strack_idx].patterns[i].fname) || !strnicmp(Soundtracks[strack_idx].patterns[i].fname, "none", 4))
|
||||
continue;
|
||||
|
||||
// check for file
|
||||
if (!cf_exists_full_ext(Soundtracks[strack_idx].patterns[i].fname, CF_TYPE_MUSIC, NUM_AUDIO_EXT, audio_ext_list))
|
||||
return;
|
||||
}
|
||||
|
||||
// made it here okay, so it's valid
|
||||
Soundtracks[strack_idx].flags |= EMF_VALID;
|
||||
}
|
||||
|
||||
void parse_menumusic()
|
||||
@@ -1579,7 +1621,7 @@ int hostile_ships_present()
|
||||
// NOTE: callers to this function are advised to allocate a 256 byte buffer
|
||||
void event_music_get_info(char *outbuf)
|
||||
{
|
||||
if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE || Current_pattern == -1 ) {
|
||||
if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE || Current_soundtrack_num < 0 || Current_pattern < 0 ) {
|
||||
strcpy(outbuf,XSTR( "Event music is not playing", 213));
|
||||
}
|
||||
else {
|
||||
@@ -1598,7 +1640,7 @@ int event_music_next_soundtrack(int delta)
|
||||
{
|
||||
int new_soundtrack;
|
||||
|
||||
if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE ) {
|
||||
if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE || Soundtracks.empty() ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1631,7 +1673,7 @@ void event_sexp_change_soundtrack(const char *name)
|
||||
}
|
||||
|
||||
event_music_level_close();
|
||||
Current_soundtrack_num = -1;
|
||||
Current_soundtrack_num = -1;
|
||||
event_music_level_start(new_soundtrack);
|
||||
}
|
||||
|
||||
@@ -1642,7 +1684,7 @@ void event_sexp_change_soundtrack(const char *name)
|
||||
// NOTE: callers to this function are advised to allocate a NAME_LENGTH buffer
|
||||
void event_music_get_soundtrack_name(char *outbuf)
|
||||
{
|
||||
if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE ) {
|
||||
if ( Event_music_enabled == FALSE || Event_music_level_inited == FALSE || Current_soundtrack_num < 0 ) {
|
||||
strcpy(outbuf, XSTR( "Event music is not playing", 213));
|
||||
}
|
||||
else {
|
||||
@@ -1653,11 +1695,15 @@ void event_music_get_soundtrack_name(char *outbuf)
|
||||
// set the current soundtrack based on name
|
||||
void event_music_set_soundtrack(const char *name)
|
||||
{
|
||||
Current_soundtrack_num = event_music_get_soundtrack_index(name);
|
||||
int index = event_music_get_soundtrack_index(name);
|
||||
|
||||
if ( Current_soundtrack_num == -1 ) {
|
||||
if (index >= 0 && Soundtracks[index].flags & EMF_VALID)
|
||||
Current_soundtrack_num = index;
|
||||
else
|
||||
Current_soundtrack_num = -1;
|
||||
|
||||
if (Current_soundtrack_num == -1)
|
||||
mprintf(("Current soundtrack set to -1 in event_music_set_soundtrack\n"));
|
||||
}
|
||||
}
|
||||
|
||||
int event_music_get_soundtrack_index(const char *name)
|
||||
@@ -1674,7 +1720,7 @@ int event_music_get_soundtrack_index(const char *name)
|
||||
|
||||
int event_music_get_spooled_music_index(const char *name)
|
||||
{
|
||||
// find the correct index for the event music
|
||||
// find the correct index for the spooled music
|
||||
for ( int i = 0; i < (int)Spooled_music.size(); i++ ) {
|
||||
if ( !stricmp(name, Spooled_music[i].name) ) {
|
||||
return i;
|
||||
@@ -1694,8 +1740,12 @@ void event_music_set_score(int score_index, const char *name)
|
||||
{
|
||||
Assert(score_index < NUM_SCORES);
|
||||
|
||||
// find the correct index for the event music
|
||||
Mission_music[score_index] = event_music_get_spooled_music_index(name);
|
||||
int index = event_music_get_spooled_music_index(name);
|
||||
|
||||
if (index >= 0 && Spooled_music[index].flags & SMF_VALID)
|
||||
Mission_music[score_index] = index;
|
||||
else
|
||||
Mission_music[score_index] = -1;
|
||||
}
|
||||
|
||||
// reset what sort of music is to be used for this mission
|
||||
|
||||
@@ -74,15 +74,16 @@ extern SCP_vector<menu_music> Spooled_music;
|
||||
|
||||
|
||||
// event music soundtrack storage
|
||||
typedef struct tagSOUNDTRACK_PATTERN_INFO {
|
||||
char fname[MAX_FILENAME_LEN];
|
||||
float num_measures;
|
||||
int samples_per_measure;
|
||||
} SOUNDTRACK_PATTERN_INFO;
|
||||
typedef struct tagSOUNDTRACK_INFO {
|
||||
int flags;
|
||||
int num_patterns;
|
||||
char name[NAME_LENGTH];
|
||||
struct {
|
||||
char fname[MAX_FILENAME_LEN];
|
||||
float num_measures;
|
||||
int samples_per_measure;
|
||||
} patterns[MAX_PATTERNS];
|
||||
SOUNDTRACK_PATTERN_INFO patterns[MAX_PATTERNS];
|
||||
} SOUNDTRACK_INFO;
|
||||
|
||||
// Goober5000 - event music flags
|
||||
|
||||
@@ -100,6 +100,20 @@ class flagset {
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename TIter>
|
||||
flagset<T>& set_multiple_from_source(const flagset<T>& source, TIter begin, TIter end) {
|
||||
auto current = begin;
|
||||
while (current != end) {
|
||||
if (source[*current]) {
|
||||
set(*current, true);
|
||||
}
|
||||
|
||||
current = std::next(current);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
flagset<T>& remove(T idx) {
|
||||
return set(idx, false);
|
||||
}
|
||||
|
||||
@@ -245,57 +245,89 @@ detail_levels Detail_defaults[NUM_DEFAULT_DETAIL_LEVELS] = {
|
||||
// Global used to access detail levels in game and libs
|
||||
detail_levels Detail = Detail_defaults[NUM_DEFAULT_DETAIL_LEVELS - 1];
|
||||
|
||||
const SCP_vector<std::pair<int, SCP_string>> DetailLevelValues = {{ 0, "Minimum" },
|
||||
{ 1, "Low" },
|
||||
{ 2, "Medium" },
|
||||
{ 3, "High" },
|
||||
{ 4, "Ultra" }, };
|
||||
const SCP_vector<std::pair<int, std::pair<const char*, int>>> DetailLevelValues = {{ 0, {"Minimum", 1680}},
|
||||
{ 1, {"Low", 1161}},
|
||||
{ 2, {"Medium", 1162}},
|
||||
{ 3, {"High", 1163}},
|
||||
{ 4, {"Ultra", 1721}}};
|
||||
|
||||
const auto ModelDetailOption __UNUSED =
|
||||
options::OptionBuilder<int>("Graphics.Detail", "Model Detail", "Detail level of models").importance(8).category(
|
||||
"Graphics").values(DetailLevelValues).default_val(MAX_DETAIL_LEVEL).change_listener([](int val, bool) {
|
||||
Detail.detail_distance = val;
|
||||
return true;
|
||||
}).finish();
|
||||
const auto ModelDetailOption __UNUSED = options::OptionBuilder<int>("Graphics.Detail",
|
||||
std::pair<const char*, int>{"Model Detail", 1739},
|
||||
std::pair<const char*, int>{"Detail level of models", 1740})
|
||||
.importance(8)
|
||||
.category("Graphics")
|
||||
.values(DetailLevelValues)
|
||||
.default_val(MAX_DETAIL_LEVEL)
|
||||
.change_listener([](int val, bool) {
|
||||
Detail.detail_distance = val;
|
||||
return true;
|
||||
})
|
||||
.finish();
|
||||
|
||||
const auto TexturesOption __UNUSED = options::OptionBuilder<int>("Graphics.Texture",
|
||||
"3D Hardware Textures",
|
||||
"Level of detail of textures").importance(6).category("Graphics").values(
|
||||
DetailLevelValues).default_val(MAX_DETAIL_LEVEL).change_listener([](int val, bool) {
|
||||
Detail.hardware_textures = val;
|
||||
return true;
|
||||
}).finish();
|
||||
std::pair<const char*, int>{"3D Hardware Textures", 1362},
|
||||
std::pair<const char*, int>{"Level of detail of textures", 1720})
|
||||
.importance(6)
|
||||
.category("Graphics")
|
||||
.values(DetailLevelValues)
|
||||
.default_val(MAX_DETAIL_LEVEL)
|
||||
.change_listener([](int val, bool) {
|
||||
Detail.hardware_textures = val;
|
||||
return true;
|
||||
})
|
||||
.finish();
|
||||
|
||||
const auto ParticlesOption __UNUSED = options::OptionBuilder<int>("Graphics.Particles",
|
||||
"Particles",
|
||||
"Level of detail for particles").importance(5).category(
|
||||
"Graphics").values(DetailLevelValues).default_val(MAX_DETAIL_LEVEL).change_listener([](int val, bool) {
|
||||
Detail.num_particles = val;
|
||||
return true;
|
||||
}).finish();
|
||||
std::pair<const char*, int>{"Particles", 1363},
|
||||
std::pair<const char*, int>{"Level of detail for particles", 1717})
|
||||
.importance(5)
|
||||
.category("Graphics")
|
||||
.values(DetailLevelValues)
|
||||
.default_val(MAX_DETAIL_LEVEL)
|
||||
.change_listener([](int val, bool) {
|
||||
Detail.num_particles = val;
|
||||
return true;
|
||||
})
|
||||
.finish();
|
||||
|
||||
const auto SmallDebrisOption __UNUSED =
|
||||
options::OptionBuilder<int>("Graphics.SmallDebris", "Impact Effects", "Level of detail of impact effects").category(
|
||||
"Graphics").values(DetailLevelValues).default_val(MAX_DETAIL_LEVEL).importance(4).change_listener([](int val,
|
||||
bool) {
|
||||
Detail.num_small_debris = val;
|
||||
return true;
|
||||
}).finish();
|
||||
const auto SmallDebrisOption __UNUSED = options::OptionBuilder<int>("Graphics.SmallDebris",
|
||||
std::pair<const char*, int>{"Impact Effects", 1364},
|
||||
std::pair<const char*, int>{"Level of detail of impact effects", 1743})
|
||||
.category("Graphics")
|
||||
.values(DetailLevelValues)
|
||||
.default_val(MAX_DETAIL_LEVEL)
|
||||
.importance(4)
|
||||
.change_listener([](int val,bool) {
|
||||
Detail.num_small_debris = val;
|
||||
return true;
|
||||
})
|
||||
.finish();
|
||||
|
||||
const auto ShieldEffectsOption __UNUSED = options::OptionBuilder<int>("Graphics.ShieldEffects",
|
||||
"Shield Hit Effects",
|
||||
"Level of detail of shield impacts").importance(3).category(
|
||||
"Graphics").values(DetailLevelValues).default_val(MAX_DETAIL_LEVEL).change_listener([](int val, bool) {
|
||||
Detail.shield_effects = val;
|
||||
return true;
|
||||
}).finish();
|
||||
std::pair<const char*, int>{"Shield Hit Effects", 1718},
|
||||
std::pair<const char*, int>{"Level of detail of shield impacts", 1719})
|
||||
.importance(3)
|
||||
.category("Graphics")
|
||||
.values(DetailLevelValues)
|
||||
.default_val(MAX_DETAIL_LEVEL)
|
||||
.change_listener([](int val, bool) {
|
||||
Detail.shield_effects = val;
|
||||
return true;
|
||||
})
|
||||
.finish();
|
||||
|
||||
const auto StarsOption __UNUSED =
|
||||
options::OptionBuilder<int>("Graphics.Stars", "Stars", "Number of stars in the mission").importance(2).category(
|
||||
"Graphics").values(DetailLevelValues).default_val(MAX_DETAIL_LEVEL).change_listener([](int val, bool) {
|
||||
Detail.num_stars = val;
|
||||
return true;
|
||||
}).finish();
|
||||
const auto StarsOption __UNUSED = options::OptionBuilder<int>("Graphics.Stars",
|
||||
std::pair<const char*, int>{"Stars", 1366},
|
||||
std::pair<const char*, int>{"Number of stars in the mission", 1698})
|
||||
.importance(2)
|
||||
.category("Graphics")
|
||||
.values(DetailLevelValues)
|
||||
.default_val(MAX_DETAIL_LEVEL)
|
||||
.change_listener([](int val, bool) {
|
||||
Detail.num_stars = val;
|
||||
return true;
|
||||
})
|
||||
.finish();
|
||||
|
||||
// Call this with:
|
||||
// 0 - lowest
|
||||
|
||||
+48
-32
@@ -53,41 +53,10 @@ version parse_version() {
|
||||
return v;
|
||||
}
|
||||
version parse_version_inline() {
|
||||
version v;
|
||||
|
||||
SCP_string input;
|
||||
stuff_string(input, F_RAW);
|
||||
|
||||
size_t start_pos = 0;
|
||||
size_t end_pos = input.find('.');
|
||||
|
||||
v.major = std::atoi(input.substr(start_pos, end_pos - start_pos).c_str());
|
||||
|
||||
if (end_pos == SCP_string::npos)
|
||||
return v;
|
||||
|
||||
start_pos = end_pos + 1;
|
||||
end_pos = input.find('.', start_pos);
|
||||
|
||||
v.minor = std::atoi(input.substr(start_pos, end_pos - start_pos).c_str());
|
||||
|
||||
if (end_pos == SCP_string::npos)
|
||||
return v;
|
||||
|
||||
start_pos = end_pos + 1;
|
||||
end_pos = input.find('.', start_pos);
|
||||
|
||||
v.build = std::atoi(input.substr(start_pos, end_pos - start_pos).c_str());
|
||||
|
||||
if (end_pos == SCP_string::npos)
|
||||
return v;
|
||||
|
||||
start_pos = end_pos + 1;
|
||||
end_pos = input.find('.', start_pos);
|
||||
|
||||
v.revision = std::atoi(input.substr(start_pos, end_pos - start_pos).c_str());
|
||||
|
||||
return v;
|
||||
return version(std::move(input), 0);
|
||||
}
|
||||
version get_executable_version() {
|
||||
version v;
|
||||
@@ -102,6 +71,53 @@ version get_executable_version() {
|
||||
version::version(int major_in, int minor_in, int build_in, int revision_in) :
|
||||
major(major_in), minor(minor_in), build(build_in), revision(revision_in) {
|
||||
}
|
||||
|
||||
version::version(const SCP_string& semver, int missing) : major(missing), minor(missing), build(missing), revision(missing) {
|
||||
int i = 0;
|
||||
auto str = semver;
|
||||
int has_fields = 0;
|
||||
while (i <= 4) {
|
||||
size_t pos = str.find_first_of('.');
|
||||
SCP_string ver;
|
||||
if (pos != SCP_string::npos) {
|
||||
ver = str.substr(0, pos);
|
||||
str.erase(0, pos + 1);
|
||||
}
|
||||
else {
|
||||
ver = str;
|
||||
str.clear();
|
||||
}
|
||||
|
||||
if (!ver.empty() && std::find_if(ver.begin(), ver.end(), [](char c) { return !std::isdigit(c, SCP_default_locale); }) == ver.end()) {
|
||||
switch (has_fields) {
|
||||
case 0:
|
||||
major = std::stoi(ver.c_str());
|
||||
++has_fields;
|
||||
break;
|
||||
case 1:
|
||||
minor = std::stoi(ver.c_str());
|
||||
++has_fields;
|
||||
break;
|
||||
case 2:
|
||||
build = std::stoi(ver.c_str());
|
||||
++has_fields;
|
||||
break;
|
||||
case 3:
|
||||
revision = std::stoi(ver.c_str());
|
||||
++has_fields;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE("Version parsing broken, get a coder!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
break; //Break out of the loop if the first string is not a digit.
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
bool version::isValid() const { return major != 0 || minor != 0 || build != 0 || revision != 0; }
|
||||
bool version::operator<(const version& v) const {
|
||||
|
||||
|
||||
@@ -57,6 +57,8 @@ struct version {
|
||||
|
||||
version(int major, int minor = 0, int build = 0, int revision = 0);
|
||||
|
||||
version(const SCP_string& semver, int missing = -1);
|
||||
|
||||
bool isValid() const;
|
||||
|
||||
bool operator<(const version& other) const;
|
||||
|
||||
+138
-128
@@ -112,35 +112,38 @@ static bool gamma_change_listener(float new_val, bool initial)
|
||||
return true;
|
||||
}
|
||||
|
||||
static auto GammaOption __UNUSED =
|
||||
options::OptionBuilder<float>("Graphics.Gamma", "Brightness", "The brighness value used for the game window")
|
||||
.category("Graphics")
|
||||
.default_val(1.0f)
|
||||
.enumerator(gamma_value_enumerator)
|
||||
.display(gamma_display)
|
||||
.change_listener(gamma_change_listener)
|
||||
.finish();
|
||||
static auto GammaOption __UNUSED = options::OptionBuilder<float>("Graphics.Gamma",
|
||||
std::pair<const char*, int>{"Brightness", 1375},
|
||||
std::pair<const char*, int>{"The brightness value used for the game window", 1738})
|
||||
.category("Graphics")
|
||||
.default_val(1.0f)
|
||||
.enumerator(gamma_value_enumerator)
|
||||
.display(gamma_display)
|
||||
.change_listener(gamma_change_listener)
|
||||
.finish();
|
||||
|
||||
|
||||
const SCP_vector<std::pair<int, SCP_string>> DetailLevelValues = {{ 0, "Minimum" },
|
||||
{ 1, "Low" },
|
||||
{ 2, "Medium" },
|
||||
{ 3, "High" },
|
||||
{ 4, "Ultra" }, };
|
||||
const SCP_vector<std::pair<int, std::pair<const char*, int>>> DetailLevelValues = {{ 0, {"Minimum", 1680}},
|
||||
{ 1, {"Low", 1161}},
|
||||
{ 2, {"Medium", 1162}},
|
||||
{ 3, {"High", 1163}},
|
||||
{ 4, {"Ultra", 1721}}};
|
||||
|
||||
const auto LightingOption __UNUSED = options::OptionBuilder<int>("Graphics.Lighting", "Lighting", "Level of detail of the lighting")
|
||||
.importance(1)
|
||||
.category("Graphics")
|
||||
.values(DetailLevelValues)
|
||||
.default_val(MAX_DETAIL_LEVEL)
|
||||
.change_listener([](int val, bool initial) {
|
||||
Detail.lighting = val;
|
||||
if (!initial) {
|
||||
gr_recompile_all_shaders(nullptr);
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.finish();
|
||||
const auto LightingOption __UNUSED = options::OptionBuilder<int>("Graphics.Lighting",
|
||||
std::pair<const char*, int>{"Lighting", 1367},
|
||||
std::pair<const char*, int>{"Level of detail of the lighting", 1715})
|
||||
.importance(1)
|
||||
.category("Graphics")
|
||||
.values(DetailLevelValues)
|
||||
.default_val(MAX_DETAIL_LEVEL)
|
||||
.change_listener([](int val, bool initial) {
|
||||
Detail.lighting = val;
|
||||
if (!initial) {
|
||||
gr_recompile_all_shaders(nullptr);
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.finish();
|
||||
|
||||
os::ViewportState Gr_configured_window_state = os::ViewportState::Windowed;
|
||||
|
||||
@@ -162,17 +165,18 @@ static bool mode_change_func(os::ViewportState state, bool initial)
|
||||
return true;
|
||||
}
|
||||
|
||||
static auto WindowModeOption __UNUSED = options::OptionBuilder<os::ViewportState>("Graphics.WindowMode", "Window Mode",
|
||||
"Controls how the game window is created.")
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.values({{os::ViewportState::Fullscreen, "Fullscreen"},
|
||||
{os::ViewportState::Borderless, "Borderless"},
|
||||
{os::ViewportState::Windowed, "Windowed"}})
|
||||
.importance(98)
|
||||
.default_val(os::ViewportState::Fullscreen)
|
||||
.change_listener(mode_change_func)
|
||||
.finish();
|
||||
static auto WindowModeOption __UNUSED = options::OptionBuilder<os::ViewportState>("Graphics.WindowMode",
|
||||
std::pair<const char*, int>{"Window Mode", 1772},
|
||||
std::pair<const char*, int>{"Controls how the game window is created", 1773})
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.values({{os::ViewportState::Fullscreen, {"Fullscreen", 1679}},
|
||||
{os::ViewportState::Borderless, {"Borderless", 1675}},
|
||||
{os::ViewportState::Windowed, {"Windowed", 1676}}})
|
||||
.importance(98)
|
||||
.default_val(os::ViewportState::Fullscreen)
|
||||
.change_listener(mode_change_func)
|
||||
.finish();
|
||||
|
||||
const std::shared_ptr<scripting::OverridableHook<>> OnFrameHook = scripting::OverridableHook<>::Factory(
|
||||
"On Frame", "Called every frame as the last action before showing the frame result to the user.", {}, tl::nullopt, CHA_ONFRAME);
|
||||
@@ -188,6 +192,7 @@ int gr_stencil_mode = 0;
|
||||
// Default clipping distances
|
||||
const float Default_min_draw_distance = 1.0f;
|
||||
const float Default_max_draw_distance = 1e10;
|
||||
float Min_draw_distance_cockpit = 0.02f;
|
||||
float Min_draw_distance = Default_min_draw_distance;
|
||||
float Max_draw_distance = Default_max_draw_distance;
|
||||
|
||||
@@ -251,18 +256,19 @@ static bool videodisplay_change(int display, bool initial)
|
||||
SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED_DISPLAY(display), SDL_WINDOWPOS_CENTERED_DISPLAY(display));
|
||||
return true;
|
||||
}
|
||||
static auto VideoDisplayOption =
|
||||
options::OptionBuilder<int>("Graphics.Display", "Primary display", "The display used for rendering.")
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.deserializer(videodisplay_deserializer)
|
||||
.serializer(videodisplay_serializer)
|
||||
.enumerator(videodisplay_enumerator)
|
||||
.display(videodisplay_display)
|
||||
.default_val(0)
|
||||
.change_listener(videodisplay_change)
|
||||
.importance(99)
|
||||
.finish();
|
||||
static auto VideoDisplayOption = options::OptionBuilder<int>("Graphics.Display",
|
||||
std::pair<const char*, int>{"Primary display", 1741},
|
||||
std::pair<const char*, int>{"The display used for rendering", 1742})
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.deserializer(videodisplay_deserializer)
|
||||
.serializer(videodisplay_serializer)
|
||||
.enumerator(videodisplay_enumerator)
|
||||
.display(videodisplay_display)
|
||||
.default_val(0)
|
||||
.change_listener(videodisplay_change)
|
||||
.importance(99)
|
||||
.finish();
|
||||
|
||||
struct ResolutionInfo {
|
||||
uint32_t width = 0;
|
||||
@@ -359,80 +365,83 @@ static bool resolution_change(const ResolutionInfo& /*info*/, bool initial)
|
||||
}
|
||||
*/
|
||||
}
|
||||
static auto ResolutionOption =
|
||||
options::OptionBuilder<ResolutionInfo>("Graphics.Resolution", "Resolution", "The rendering resolution.")
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.deserializer(resolution_deserializer)
|
||||
.serializer(resolution_serializer)
|
||||
.enumerator(resolution_enumerator)
|
||||
.display(resolution_display)
|
||||
.default_func(resolution_default)
|
||||
.change_listener(resolution_change)
|
||||
.importance(100)
|
||||
.finish();
|
||||
static auto ResolutionOption = options::OptionBuilder<ResolutionInfo>("Graphics.Resolution",
|
||||
std::pair<const char*, int>{"Resolution", 1748},
|
||||
std::pair<const char*, int>{"The rendering resolution", 1749})
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Beginner)
|
||||
.deserializer(resolution_deserializer)
|
||||
.serializer(resolution_serializer)
|
||||
.enumerator(resolution_enumerator)
|
||||
.display(resolution_display)
|
||||
.default_func(resolution_default)
|
||||
.change_listener(resolution_change)
|
||||
.importance(100)
|
||||
.finish();
|
||||
|
||||
bool Gr_enable_soft_particles = false;
|
||||
|
||||
static auto SoftParticlesOption __UNUSED = options::OptionBuilder<bool>("Graphics.SoftParticles", "Soft Particles",
|
||||
"Enable or disable soft particle rendering.")
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.default_val(true)
|
||||
.bind_to_once(&Gr_enable_soft_particles)
|
||||
.importance(68)
|
||||
.finish();
|
||||
static auto SoftParticlesOption __UNUSED = options::OptionBuilder<bool>("Graphics.SoftParticles",
|
||||
std::pair<const char*, int>{"Soft Particles", 1761},
|
||||
std::pair<const char*, int>{"Enable or disable soft particle rendering", 1762})
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.default_val(true)
|
||||
.bind_to_once(&Gr_enable_soft_particles)
|
||||
.importance(68)
|
||||
.finish();
|
||||
|
||||
flagset<FramebufferEffects> Gr_framebuffer_effects;
|
||||
|
||||
static auto FramebufferEffectsOption __UNUSED =
|
||||
options::OptionBuilder<flagset<FramebufferEffects>>(
|
||||
"Graphics.FramebufferEffects", "Framebuffer effects",
|
||||
"Controls which framebuffer effects will be applied to the scene.")
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.values({{{}, "None"},
|
||||
{{FramebufferEffects::Shockwaves}, "Shockwaves"},
|
||||
{{FramebufferEffects::Thrusters}, "Thrusters"},
|
||||
{{FramebufferEffects::Shockwaves, FramebufferEffects::Thrusters}, "All"}})
|
||||
.default_val({FramebufferEffects::Shockwaves, FramebufferEffects::Thrusters})
|
||||
.bind_to_once(&Gr_framebuffer_effects)
|
||||
.importance(77)
|
||||
.finish();
|
||||
static auto FramebufferEffectsOption __UNUSED = options::OptionBuilder<flagset<FramebufferEffects>>("Graphics.FramebufferEffects",
|
||||
std::pair<const char*, int>{"Framebuffer effects", 1732},
|
||||
std::pair<const char*, int>{"Controls which framebuffer effects will be applied to the scene", 1733})
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.values({{{}, {"None", 211}},
|
||||
{{FramebufferEffects::Shockwaves}, {"Shockwaves", 1688}},
|
||||
{{FramebufferEffects::Thrusters}, {"Thrusters", 1689}},
|
||||
{{FramebufferEffects::Shockwaves, FramebufferEffects::Thrusters}, {"All", 1690}}})
|
||||
.default_val({FramebufferEffects::Shockwaves, FramebufferEffects::Thrusters})
|
||||
.bind_to_once(&Gr_framebuffer_effects)
|
||||
.importance(77)
|
||||
.finish();
|
||||
|
||||
AntiAliasMode Gr_aa_mode = AntiAliasMode::None;
|
||||
AntiAliasMode Gr_aa_mode_last_frame = AntiAliasMode::None;
|
||||
|
||||
static auto AAOption __UNUSED = options::OptionBuilder<AntiAliasMode>("Graphics.AAMode", "Anti Aliasing",
|
||||
"Controls the anti aliasing mode of the engine.")
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.values({{AntiAliasMode::None, "None"},
|
||||
{AntiAliasMode::FXAA_Low, "FXAA Low"},
|
||||
{AntiAliasMode::FXAA_Medium, "FXAA Medium"},
|
||||
{AntiAliasMode::FXAA_High, "FXAA High"},
|
||||
{AntiAliasMode::SMAA_Low, "SMAA Low"},
|
||||
{AntiAliasMode::SMAA_Medium, "SMAA Medium"},
|
||||
{AntiAliasMode::SMAA_High, "SMAA High"},
|
||||
{AntiAliasMode::SMAA_Ultra, "SMAA Ultra"}})
|
||||
.default_val(AntiAliasMode::None)
|
||||
.bind_to(&Gr_aa_mode)
|
||||
.importance(79)
|
||||
.finish();
|
||||
static auto AAOption __UNUSED = options::OptionBuilder<AntiAliasMode>("Graphics.AAMode",
|
||||
std::pair<const char*, int>{"Anti Aliasing", 1752},
|
||||
std::pair<const char*, int>{"Controls the anti aliasing mode of the engine.", 1753})
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.values({{AntiAliasMode::None, {"None", 211}},
|
||||
{AntiAliasMode::FXAA_Low, {"FXAA Low", 1681}},
|
||||
{AntiAliasMode::FXAA_Medium, {"FXAA Medium", 1682}},
|
||||
{AntiAliasMode::FXAA_High, {"FXAA High", 1683}},
|
||||
{AntiAliasMode::SMAA_Low, {"SMAA Low", 1684}},
|
||||
{AntiAliasMode::SMAA_Medium, {"SMAA Medium", 1685}},
|
||||
{AntiAliasMode::SMAA_High, {"SMAA High", 1686}},
|
||||
{AntiAliasMode::SMAA_Ultra, {"SMAA Ultra", 1687}}})
|
||||
.default_val(AntiAliasMode::None)
|
||||
.bind_to(&Gr_aa_mode)
|
||||
.importance(79)
|
||||
.finish();
|
||||
|
||||
extern int Cmdline_msaa_enabled;
|
||||
static auto MSAAOption __UNUSED = options::OptionBuilder<int>("Graphics.MSAASamples", "Multisample Anti Aliasing",
|
||||
"Controls whether multisample anti aliasing is enabled, and with how many samples.")
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.values({{0, "Off"},
|
||||
{4, "4 Samples"},
|
||||
{8, "8 Samples"},
|
||||
{16, "16 Samples"}})
|
||||
.default_val(0)
|
||||
.bind_to(&Cmdline_msaa_enabled)
|
||||
.importance(78)
|
||||
.finish();
|
||||
static auto MSAAOption __UNUSED = options::OptionBuilder<int>("Graphics.MSAASamples",
|
||||
std::pair<const char*, int>{"Multisample Anti Aliasing", 1758},
|
||||
std::pair<const char*, int>{"Controls whether multisample anti asliasing is enabled, and with how many samples", 1759})
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.values({{0, {"Off", 1693}},
|
||||
{4, {"4 Samples", 1694}},
|
||||
{8, {"8 Samples", 1695}},
|
||||
{16, {"16 Samples", 1696}}})
|
||||
.default_val(0)
|
||||
.bind_to_once(&Cmdline_msaa_enabled)
|
||||
.importance(78)
|
||||
.finish();
|
||||
|
||||
bool gr_is_fxaa_mode(AntiAliasMode mode)
|
||||
{
|
||||
@@ -444,26 +453,27 @@ bool gr_is_smaa_mode(AntiAliasMode mode) {
|
||||
|
||||
bool Gr_post_processing_enabled = true;
|
||||
|
||||
static auto PostProcessOption __UNUSED =
|
||||
options::OptionBuilder<bool>("Graphics.PostProcessing", "Post processing",
|
||||
"Controls whether post processing is enabled in the engine")
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.default_val(false)
|
||||
.bind_to_once(&Gr_post_processing_enabled)
|
||||
.importance(69)
|
||||
.finish();
|
||||
static auto PostProcessOption __UNUSED = options::OptionBuilder<bool>("Graphics.PostProcessing",
|
||||
std::pair<const char*, int>{"Post processing", 1726},
|
||||
std::pair<const char*, int>{"Controls whether post processing is enabled in the engine.", 1727})
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.default_val(false)
|
||||
.bind_to_once(&Gr_post_processing_enabled)
|
||||
.importance(69)
|
||||
.finish();
|
||||
|
||||
bool Gr_enable_vsync = true;
|
||||
|
||||
static auto VSyncOption __UNUSED = options::OptionBuilder<bool>("Graphics.VSync", "Vertical Sync",
|
||||
"Controls how the engine does vertical synchronization")
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.default_val(true)
|
||||
.bind_to_once(&Gr_enable_vsync)
|
||||
.importance(70)
|
||||
.finish();
|
||||
static auto VSyncOption __UNUSED = options::OptionBuilder<bool>("Graphics.VSync",
|
||||
std::pair<const char*, int>{"Vertical Sync", 1766},
|
||||
std::pair<const char*, int>{"Controls how the engine does vertical synchronization", 1767})
|
||||
.category("Graphics")
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.default_val(true)
|
||||
.bind_to_once(&Gr_enable_vsync)
|
||||
.importance(70)
|
||||
.finish();
|
||||
|
||||
static std::unique_ptr<graphics::util::UniformBufferManager> UniformBufferManager;
|
||||
|
||||
|
||||
+4
-3
@@ -36,6 +36,7 @@ class OverridableHook;
|
||||
|
||||
extern const float Default_min_draw_distance;
|
||||
extern const float Default_max_draw_distance;
|
||||
extern float Min_draw_distance_cockpit;
|
||||
extern float Min_draw_distance;
|
||||
extern float Max_draw_distance;
|
||||
extern int Gr_inited;
|
||||
@@ -102,7 +103,7 @@ public:
|
||||
Stack.push_back(Current_transform);
|
||||
}
|
||||
|
||||
matrix4 &get_transform()
|
||||
const matrix4 &get_transform() const
|
||||
{
|
||||
return Current_transform;
|
||||
}
|
||||
@@ -115,7 +116,7 @@ public:
|
||||
Stack.push_back(Current_transform);
|
||||
}
|
||||
|
||||
void push_and_replace(matrix4 new_transform)
|
||||
void push_and_replace(const matrix4 &new_transform)
|
||||
{
|
||||
Current_transform = new_transform;
|
||||
Stack.push_back(Current_transform);
|
||||
@@ -300,7 +301,7 @@ public:
|
||||
|
||||
void add_vertex_component(vertex_format_data::vertex_format format_type, size_t stride, size_t offset);
|
||||
|
||||
size_t get_vertex_stride() { return Vertex_stride; }
|
||||
size_t get_vertex_stride() const { return Vertex_stride; }
|
||||
|
||||
bool operator==(const vertex_layout& other) const;
|
||||
|
||||
|
||||
@@ -519,7 +519,7 @@ void generic_render_png_stream(generic_anim* ga)
|
||||
* @param [in] *ga animation data
|
||||
* @param [in] frametime how long this frame took
|
||||
*/
|
||||
void generic_anim_render_fixed_frame_delay(generic_anim* ga, float frametime)
|
||||
void generic_anim_render_fixed_frame_delay(generic_anim* ga, float frametime, float alpha = 1.0f)
|
||||
{
|
||||
float keytime = 0.0;
|
||||
|
||||
@@ -580,10 +580,19 @@ void generic_anim_render_fixed_frame_delay(generic_anim* ga, float frametime)
|
||||
} else {
|
||||
generic_render_eff_stream(ga);
|
||||
}
|
||||
gr_set_bitmap(ga->bitmap_id);
|
||||
|
||||
if (alpha == 1.0f) {
|
||||
gr_set_bitmap(ga->bitmap_id);
|
||||
} else {
|
||||
gr_set_bitmap(ga->bitmap_id, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, alpha);
|
||||
}
|
||||
}
|
||||
else {
|
||||
gr_set_bitmap(ga->first_frame + ga->current_frame);
|
||||
if (alpha == 1.0f) {
|
||||
gr_set_bitmap(ga->first_frame + ga->current_frame);
|
||||
} else {
|
||||
gr_set_bitmap(ga->first_frame + ga->current_frame, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, alpha);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -703,7 +712,7 @@ void generic_anim_render(generic_anim *ga, float frametime, int x, int y, bool m
|
||||
generic_anim_render_variable_frame_delay(ga, frametime, a);
|
||||
}
|
||||
else {
|
||||
generic_anim_render_fixed_frame_delay(ga, frametime);
|
||||
generic_anim_render_fixed_frame_delay(ga, frametime, a);
|
||||
}
|
||||
|
||||
if(ga->num_frames > 0) {
|
||||
@@ -719,7 +728,44 @@ void generic_anim_render(generic_anim *ga, float frametime, int x, int y, bool m
|
||||
else if (ge->draw == true) {
|
||||
// currently only for lua streaminganim objects
|
||||
// and don't draw them unless requested...
|
||||
gr_bitmap_uv(x, y, ge->width, ge->height, ge->u0, ge->v0, ge->u1, ge->v1, GR_RESIZE_NONE);
|
||||
gr_bitmap_uv(x, y, ge->width, ge->height, ge->u0, ge->v0, ge->u1, ge->v1, ge->resize_mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void generic_anim_render_ex(generic_anim* ga, float frametime, int x, int y, int w, int h, bool menu, const generic_extras* ge)
|
||||
{
|
||||
if ((ge != nullptr) && (ga->use_hud_color == true)) {
|
||||
Warning(LOCATION, "Monochrome generic anims can't use extra info (yet)");
|
||||
return;
|
||||
}
|
||||
|
||||
float a = 1.0f;
|
||||
if (ge != nullptr) {
|
||||
a = ge->alpha;
|
||||
}
|
||||
if (ga->type == BM_TYPE_PNG) {
|
||||
generic_anim_render_variable_frame_delay(ga, frametime, a);
|
||||
}
|
||||
else {
|
||||
generic_anim_render_fixed_frame_delay(ga, frametime, a);
|
||||
}
|
||||
|
||||
if (ga->num_frames > 0) {
|
||||
ga->previous_frame = ga->current_frame;
|
||||
|
||||
if (ga->use_hud_color) {
|
||||
gr_aabitmap_ex(x, y, w, h, 0, 0, (menu ? GR_RESIZE_MENU : GR_RESIZE_FULL));
|
||||
}
|
||||
else {
|
||||
if (ge == nullptr) {
|
||||
gr_bitmap_ex(x, y, w, h, 0, 0, (menu ? GR_RESIZE_MENU : GR_RESIZE_FULL));
|
||||
}
|
||||
else if (ge->draw == true) {
|
||||
// currently only for lua streaminganim objects
|
||||
// and don't draw them unless requested...
|
||||
gr_bitmap_uv(x, y, w, h, ge->u0, ge->v0, ge->u1, ge->v1, ge->resize_mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,6 +67,7 @@ public:
|
||||
float u0, v0, u1, v1;
|
||||
float alpha;
|
||||
bool draw;
|
||||
int resize_mode;
|
||||
|
||||
generic_extras()
|
||||
: width(0), height(0)
|
||||
@@ -74,6 +75,7 @@ public:
|
||||
, u1(1.0f), v1(1.0f)
|
||||
, alpha(1.0f)
|
||||
, draw(true)
|
||||
, resize_mode(0) // GR_RESIZE_NONE
|
||||
{}
|
||||
};
|
||||
|
||||
@@ -89,5 +91,6 @@ int generic_anim_stream(generic_anim *ga, const bool cache = true);
|
||||
int generic_bitmap_load(generic_bitmap *gb);
|
||||
void generic_anim_unload(generic_anim *ga);
|
||||
void generic_anim_render(generic_anim *ga, float frametime, int x, int y, bool menu = false, const generic_extras *ge = nullptr);
|
||||
void generic_anim_render_ex(generic_anim* ga, float frametime, int x, int y, int w, int h, bool menu = false, const generic_extras* ge = nullptr);
|
||||
void generic_anim_reset(generic_anim *ga);
|
||||
#endif
|
||||
@@ -441,7 +441,7 @@ void material::set_color(int r, int g, int b, int a)
|
||||
Clr.xyzw.w = i2fl(a) / 255.0f;
|
||||
}
|
||||
|
||||
void material::set_color(color &clr_in)
|
||||
void material::set_color(const color &clr_in)
|
||||
{
|
||||
if ( clr_in.is_alphacolor ) {
|
||||
Clr.xyzw.x = i2fl(clr_in.red) / 255.0f;
|
||||
|
||||
@@ -133,7 +133,7 @@ public:
|
||||
|
||||
void set_color(float red, float green, float blue, float alpha);
|
||||
void set_color(int r, int g, int b, int a);
|
||||
void set_color(color &clr_in);
|
||||
void set_color(const color &clr_in);
|
||||
const vec4& get_color() const;
|
||||
|
||||
void set_color_scale(float scale);
|
||||
|
||||
+27
-10
@@ -16,6 +16,8 @@ matrix4 gr_texture_matrix;
|
||||
|
||||
matrix4 gr_env_texture_matrix;
|
||||
|
||||
float gr_near_plane;
|
||||
|
||||
bool gr_htl_projection_matrix_set = false;
|
||||
|
||||
static int modelview_matrix_depth = 1;
|
||||
@@ -116,28 +118,43 @@ void gr_end_instance_matrix()
|
||||
}
|
||||
|
||||
// the projection matrix; fov, aspect ratio, near, far
|
||||
void gr_set_proj_matrix(float fov, float aspect, float z_near, float z_far) {
|
||||
void gr_set_proj_matrix(fov_t fov, float aspect, float z_near, float z_far) {
|
||||
if (gr_screen.rendering_to_texture != -1) {
|
||||
gr_set_viewport(gr_screen.offset_x, gr_screen.offset_y, gr_screen.clip_width, gr_screen.clip_height);
|
||||
} else {
|
||||
gr_set_viewport(gr_screen.offset_x, (gr_screen.max_h - gr_screen.offset_y - gr_screen.clip_height), gr_screen.clip_width, gr_screen.clip_height);
|
||||
}
|
||||
|
||||
float clip_width, clip_height;
|
||||
|
||||
clip_height = tan( fov * 0.5f ) * z_near;
|
||||
clip_width = clip_height * aspect;
|
||||
|
||||
gr_last_projection_matrix = gr_projection_matrix;
|
||||
if (gr_screen.rendering_to_texture != -1) {
|
||||
create_perspective_projection_matrix(&gr_projection_matrix, -clip_width, clip_width, clip_height, -clip_height, z_near, z_far);
|
||||
} else {
|
||||
create_perspective_projection_matrix(&gr_projection_matrix, -clip_width, clip_width, -clip_height, clip_height, z_near, z_far);
|
||||
|
||||
if (mpark::holds_alternative<float>(fov)) {
|
||||
float clip_width, clip_height;
|
||||
clip_height = tan(mpark::get<float>(fov) * 0.5f) * z_near;
|
||||
clip_width = clip_height * aspect;
|
||||
if (gr_screen.rendering_to_texture != -1) {
|
||||
create_perspective_projection_matrix(&gr_projection_matrix, -clip_width, clip_width, clip_height, -clip_height, z_near, z_far);
|
||||
} else {
|
||||
create_perspective_projection_matrix(&gr_projection_matrix, -clip_width, clip_width, -clip_height, clip_height, z_near, z_far);
|
||||
}
|
||||
}
|
||||
else {
|
||||
const auto& afov = mpark::get<asymmetric_fov>(fov);
|
||||
float clip_l = tanf(afov.left) * z_near;
|
||||
float clip_r = tanf(afov.right) * z_near;
|
||||
float clip_u = tanf(afov.up) * z_near;
|
||||
float clip_d = tanf(afov.down) * z_near;
|
||||
if (gr_screen.rendering_to_texture != -1) {
|
||||
create_perspective_projection_matrix(&gr_projection_matrix, clip_l, clip_r, clip_u, clip_d, z_near, z_far);
|
||||
}
|
||||
else {
|
||||
create_perspective_projection_matrix(&gr_projection_matrix, clip_l, clip_r, clip_d, clip_u, z_near, z_far);
|
||||
}
|
||||
}
|
||||
|
||||
gr_htl_projection_matrix_set = true;
|
||||
|
||||
matrix_uniform_up_to_date = false;
|
||||
gr_near_plane = z_near;
|
||||
}
|
||||
|
||||
void gr_end_proj_matrix() {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "graphics/2d.h"
|
||||
#include "render/3d.h"
|
||||
|
||||
extern transform_stack gr_model_matrix_stack;
|
||||
extern matrix4 gr_view_matrix;
|
||||
@@ -8,6 +9,7 @@ extern matrix4 gr_model_view_matrix;
|
||||
extern matrix4 gr_projection_matrix;
|
||||
extern matrix4 gr_last_projection_matrix;
|
||||
extern matrix4 gr_env_texture_matrix;
|
||||
extern float gr_near_plane;
|
||||
|
||||
void gr_matrix_on_frame();
|
||||
|
||||
@@ -15,7 +17,7 @@ void gr_start_instance_matrix(const vec3d* offset, const matrix* rotation);
|
||||
void gr_start_angles_instance_matrix(const vec3d* pos, const angles* rotation);
|
||||
void gr_end_instance_matrix();
|
||||
|
||||
void gr_set_proj_matrix(float fov, float aspect, float z_near, float z_far);
|
||||
void gr_set_proj_matrix(fov_t fov, float aspect, float z_near, float z_far);
|
||||
void gr_end_proj_matrix();
|
||||
|
||||
void gr_set_view_matrix(const vec3d* pos, const matrix* orient);
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "graphics/2d.h"
|
||||
#include "graphics/matrix.h"
|
||||
#include "libs/renderdoc/renderdoc.h"
|
||||
#include "lighting/lighting.h"
|
||||
#include "math/floating.h"
|
||||
#include "model/model.h"
|
||||
#include "options/Option.h"
|
||||
@@ -861,6 +862,9 @@ int opengl_init_display_device()
|
||||
}
|
||||
}
|
||||
|
||||
if (Cmdline_capture_mouse)
|
||||
attrs.flags.set(os::ViewPortFlags::Capture_Mouse);
|
||||
|
||||
auto viewport = gr_opengl_create_viewport(attrs);
|
||||
if (!viewport) {
|
||||
return 1;
|
||||
@@ -1177,7 +1181,7 @@ static void init_extensions() {
|
||||
|
||||
// we require a minimum GLSL version
|
||||
if (GLSL_version < MIN_REQUIRED_GLSL_VERSION) {
|
||||
Error(LOCATION, "Current GL Shading Langauge Version of %d is less than the required version of %d. Switch video modes or update your drivers.", GLSL_version, MIN_REQUIRED_GLSL_VERSION);
|
||||
Error(LOCATION, "Current GL Shading Language Version of %d is less than the required version of %d. Switch video modes or update your drivers.", GLSL_version, MIN_REQUIRED_GLSL_VERSION);
|
||||
}
|
||||
|
||||
GLint max_texture_units;
|
||||
@@ -1399,7 +1403,7 @@ bool gr_opengl_is_capable(gr_capability capability)
|
||||
case CAPABILITY_POST_PROCESSING:
|
||||
return Gr_post_processing_enabled && !Cmdline_no_fbo;
|
||||
case CAPABILITY_DEFERRED_LIGHTING:
|
||||
return !Cmdline_no_fbo && !Cmdline_no_deferred_lighting;
|
||||
return !Cmdline_no_fbo && light_deferred_enabled();
|
||||
case CAPABILITY_SHADOWS:
|
||||
case CAPABILITY_THICK_OUTLINE:
|
||||
return !Cmdline_no_geo_sdr_effects;
|
||||
|
||||
@@ -57,7 +57,7 @@ void opengl_clear_deferred_buffers()
|
||||
|
||||
void gr_opengl_deferred_lighting_begin(bool clearNonColorBufs)
|
||||
{
|
||||
if ( Cmdline_no_deferred_lighting)
|
||||
if (!light_deferred_enabled())
|
||||
return;
|
||||
|
||||
static const float black[] = {0, 0, 0, 1.0f};
|
||||
@@ -149,7 +149,7 @@ void gr_opengl_deferred_lighting_msaa()
|
||||
opengl_set_generic_uniform_data<graphics::generic_data::msaa_data>(
|
||||
[&](graphics::generic_data::msaa_data* data) {
|
||||
data->samples = Cmdline_msaa_enabled;
|
||||
data->fov = Proj_fov;
|
||||
data->fov = g3_get_hfov(Proj_fov);
|
||||
});
|
||||
GL_state.SetAlphaBlendMode(gr_alpha_blend::ALPHA_BLEND_NONE);
|
||||
GL_state.SetZbufferType(ZBUFFER_TYPE_WRITE);
|
||||
@@ -181,7 +181,7 @@ void gr_opengl_deferred_lighting_finish()
|
||||
GR_DEBUG_SCOPE("Deferred lighting finish");
|
||||
TRACE_SCOPE(tracing::ApplyLights);
|
||||
|
||||
if (Cmdline_no_deferred_lighting) {
|
||||
if (!light_deferred_enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -254,6 +254,7 @@ void gr_opengl_deferred_lighting_finish()
|
||||
|
||||
header->invScreenWidth = 1.0f / gr_screen.max_w;
|
||||
header->invScreenHeight = 1.0f / gr_screen.max_h;
|
||||
header->nearPlane = gr_near_plane;
|
||||
|
||||
// Only the first directional light uses shaders so we need to know when we already saw that light
|
||||
bool first_directional = true;
|
||||
@@ -480,7 +481,7 @@ void gr_opengl_deferred_lighting_finish()
|
||||
data->noiseColorScale2 = std::get<1>(neb.getNoiseColorScale());
|
||||
data->noiseColorIntensity = neb.getNoiseColorIntensity();
|
||||
data->aspect = gr_screen.clip_aspect;
|
||||
data->fov = Proj_fov;
|
||||
data->fov = g3_get_hfov(Proj_fov);
|
||||
});
|
||||
|
||||
{
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "graphics/matrix.h"
|
||||
#include "graphics/paths/PathRenderer.h"
|
||||
#include "graphics/util/uniform_structs.h"
|
||||
#include "lighting/lighting.h"
|
||||
#include "render/3d.h"
|
||||
#include "tracing/tracing.h"
|
||||
|
||||
@@ -673,7 +674,7 @@ void gr_opengl_scene_texture_begin()
|
||||
Scene_texture_v_scale = 1.0f;
|
||||
}
|
||||
|
||||
if ( Cmdline_no_deferred_lighting ) {
|
||||
if (!light_deferred_enabled()) {
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
} else {
|
||||
|
||||
@@ -398,7 +398,7 @@ static void handle_includes_impl(SCP_vector<SCP_string>& include_stack,
|
||||
|
||||
if (first_quote == SCP_string::npos || second_quote == SCP_string::npos) {
|
||||
Error(LOCATION,
|
||||
"Shader %s:%d: Malformed include line. Could not find both quote charaters.",
|
||||
"Shader %s:%d: Malformed include line. Could not find both quote characters.",
|
||||
filename.c_str(),
|
||||
line_num);
|
||||
}
|
||||
|
||||
@@ -47,17 +47,19 @@ extern int GLOWMAP;
|
||||
extern int SPECMAP;
|
||||
extern int ENVMAP;
|
||||
|
||||
const SCP_vector<std::pair<int, SCP_string>> TextureFilteringValues = {{ 0, "Bilinear" },
|
||||
{ 1, "Trilinear" }, };
|
||||
const SCP_vector<std::pair<int, std::pair<const char*, int>>> TextureFilteringValues = {{0, {"Bilinear", 1677}},
|
||||
{ 1, {"Trilinear", 1678}}};
|
||||
|
||||
static auto TextureFilteringOption __UNUSED = options::OptionBuilder<int>("Graphics.TextureFilter", "Texture Filtering", "Texture filtering option")
|
||||
.importance(1)
|
||||
.category("Graphics")
|
||||
.values(TextureFilteringValues)
|
||||
.default_val(0)
|
||||
.bind_to_once(&GL_mipmap_filter)
|
||||
.flags({options::OptionFlags::ForceMultiValueSelection})
|
||||
.finish();
|
||||
static auto TextureFilteringOption __UNUSED = options::OptionBuilder<int>("Graphics.TextureFilter",
|
||||
std::pair<const char*, int>{"Texture Filtering", 1763},
|
||||
std::pair<const char*, int>{"Texture filtering option", 1764})
|
||||
.importance(1)
|
||||
.category("Graphics")
|
||||
.values(TextureFilteringValues)
|
||||
.default_val(0)
|
||||
.bind_to_once(&GL_mipmap_filter)
|
||||
.flags({options::OptionFlags::ForceMultiValueSelection})
|
||||
.finish();
|
||||
|
||||
static SCP_vector<float> anisotropic_value_enumerator()
|
||||
{
|
||||
@@ -100,16 +102,16 @@ static float anisotropic_default()
|
||||
return max;
|
||||
}
|
||||
|
||||
static auto AnisotropyOption =
|
||||
options::OptionBuilder<float>("Graphics.Anisotropy", "Anisotropic filtering",
|
||||
"Controls the amount of anisotropic filtering of the textures.")
|
||||
.enumerator(anisotropic_value_enumerator)
|
||||
.category("Graphics")
|
||||
.display(anisotropic_display)
|
||||
.default_func(anisotropic_default)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.importance(78)
|
||||
.finish();
|
||||
static auto AnisotropyOption = options::OptionBuilder<float>("Graphics.Anisotropy",
|
||||
std::pair<const char*, int>{"Anistropic filtering", 1736},
|
||||
std::pair<const char*, int>{"Controls the amount of anistropic filtering of the textures", 1737})
|
||||
.enumerator(anisotropic_value_enumerator)
|
||||
.category("Graphics")
|
||||
.display(anisotropic_display)
|
||||
.default_func(anisotropic_default)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.importance(78)
|
||||
.finish();
|
||||
|
||||
// forward declarations
|
||||
int opengl_free_texture(tcache_slot_opengl *t);
|
||||
|
||||
@@ -974,7 +974,7 @@ void opengl_tnl_set_material_particle(particle_material * material_info)
|
||||
data->srgb = High_dynamic_range ? 1 : 0;
|
||||
data->blend_alpha = material_info->get_blend_mode() != ALPHA_BLEND_ADDITIVE;
|
||||
|
||||
if (Cmdline_no_deferred_lighting) {
|
||||
if (!light_deferred_enabled()) {
|
||||
data->linear_depth = 0;
|
||||
} else {
|
||||
data->linear_depth = 1;
|
||||
@@ -984,7 +984,7 @@ void opengl_tnl_set_material_particle(particle_material * material_info)
|
||||
Current_shader->program->Uniforms.setTextureUniform("baseMap", 0);
|
||||
Current_shader->program->Uniforms.setTextureUniform("depthMap", 1);
|
||||
|
||||
if (!Cmdline_no_deferred_lighting) {
|
||||
if (light_deferred_enabled()) {
|
||||
Assert(Scene_position_texture != 0);
|
||||
|
||||
GL_state.Texture.Enable(1, GL_TEXTURE_2D, Scene_position_texture);
|
||||
|
||||
@@ -40,27 +40,28 @@ PostEffectUniformType mapUniformNameToType(const SCP_string& uniform_name)
|
||||
// used by In-Game Options menu
|
||||
bool Post_processing_enable_lightshafts = true;
|
||||
|
||||
auto LightshaftsOption __UNUSED =
|
||||
options::OptionBuilder<bool>("Graphics.Lightshafts", "Lightshafts", "Enable lightshafts (requires post-processing)")
|
||||
.category("Graphics")
|
||||
.default_val(true)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.bind_to(&Post_processing_enable_lightshafts)
|
||||
.importance(60)
|
||||
.finish();
|
||||
static auto LightshaftsOption __UNUSED = options::OptionBuilder<bool>("Graphics.Lightshafts",
|
||||
std::pair<const char*, int>{"Lightshafts", 1724},
|
||||
std::pair<const char*, int>{"Enables or disables lightshafts (requires post-processing)", 1725})
|
||||
.category("Graphics")
|
||||
.default_val(true)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.bind_to(&Post_processing_enable_lightshafts)
|
||||
.importance(60)
|
||||
.finish();
|
||||
|
||||
int Post_processing_bloom_intensity = 25; // using default value of Cmdline_bloom_intensity
|
||||
|
||||
auto BloomIntensityOption __UNUSED = options::OptionBuilder<int>("Graphics.BloomIntensity",
|
||||
"Bloom intensity",
|
||||
"Set bloom intensity (requires post-processing)")
|
||||
.category("Graphics")
|
||||
.range(0, 200)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.default_val(25)
|
||||
.bind_to(&Post_processing_bloom_intensity)
|
||||
.importance(55)
|
||||
.finish();
|
||||
static auto BloomIntensityOption __UNUSED = options::OptionBuilder<int>("Graphics.BloomIntensity",
|
||||
std::pair<const char*, int>{"Bloom intensity", 1701},
|
||||
std::pair<const char*, int>{"Sets the bloom intensity (requires post-processing)", 1702})
|
||||
.category("Graphics")
|
||||
.range(0, 200)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.default_val(25)
|
||||
.bind_to(&Post_processing_bloom_intensity)
|
||||
.importance(55)
|
||||
.finish();
|
||||
} // namespace
|
||||
|
||||
bool PostProcessingManager::parse_table()
|
||||
@@ -223,7 +224,7 @@ bool gr_lightshafts_enabled()
|
||||
}
|
||||
|
||||
if (Using_in_game_options) {
|
||||
return graphics::Post_processing_enable_lightshafts;
|
||||
return graphics::LightshaftsOption->getValue();
|
||||
} else {
|
||||
return !Cmdline_force_lightshaft_off;
|
||||
}
|
||||
@@ -240,7 +241,7 @@ int gr_bloom_intensity()
|
||||
}
|
||||
|
||||
if (Using_in_game_options) {
|
||||
return graphics::Post_processing_bloom_intensity;
|
||||
return graphics::BloomIntensityOption->getValue();
|
||||
} else {
|
||||
return Cmdline_bloom_intensity;
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ static void bitmap_ex_internal(int x,
|
||||
bool aabitmap,
|
||||
bool mirror,
|
||||
color* clr,
|
||||
int scale = 100) {
|
||||
float scale_factor = 1.0f) {
|
||||
if ((w < 1) || (h < 1)) {
|
||||
return;
|
||||
}
|
||||
@@ -118,8 +118,10 @@ static void bitmap_ex_internal(int x,
|
||||
|
||||
bm_get_info(gr_screen.current_bitmap, &bw, &bh);
|
||||
|
||||
bw = (bw * scale) / 100;
|
||||
bh = (bh * scale) / 100;
|
||||
if (scale_factor != 1.0f) {
|
||||
bw = static_cast<int>(bw * scale_factor);
|
||||
bh = static_cast<int>(bh * scale_factor);
|
||||
}
|
||||
|
||||
u0 = (i2fl(sx) / i2fl(bw));
|
||||
v0 = (i2fl(sy) / i2fl(bh));
|
||||
@@ -163,7 +165,7 @@ static void bitmap_ex_internal(int x,
|
||||
draw_textured_quad(&render_mat, x1, y1, u0, v0, x2, y2, u1, v1);
|
||||
}
|
||||
|
||||
void gr_aabitmap(int x, int y, int resize_mode, bool mirror, int scale) {
|
||||
void gr_aabitmap(int x, int y, int resize_mode, bool mirror, float scale_factor) {
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
return;
|
||||
}
|
||||
@@ -174,8 +176,10 @@ void gr_aabitmap(int x, int y, int resize_mode, bool mirror, int scale) {
|
||||
|
||||
bm_get_info(gr_screen.current_bitmap, &w, &h);
|
||||
|
||||
w = (w * scale) / 100;
|
||||
h = (h * scale) / 100;
|
||||
if (scale_factor != 1.0f) {
|
||||
w = static_cast<int>(w * scale_factor);
|
||||
h = static_cast<int>(h * scale_factor);
|
||||
}
|
||||
|
||||
if (resize_mode != GR_RESIZE_NONE && (gr_screen.custom_size || (gr_screen.rendering_to_texture != -1))) {
|
||||
do_resize = 1;
|
||||
@@ -239,7 +243,7 @@ void gr_aabitmap(int x, int y, int resize_mode, bool mirror, int scale) {
|
||||
true,
|
||||
mirror,
|
||||
&gr_screen.current_color,
|
||||
scale);
|
||||
scale_factor);
|
||||
}
|
||||
void gr_aabitmap_ex(int x, int y, int w, int h, int sx, int sy, int resize_mode, bool mirror) {
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
|
||||
@@ -25,8 +25,9 @@ void gr_flash_alpha(int r, int g, int b, int a);
|
||||
* @param y The y-coordinate of the draw call
|
||||
* @param resize_mode The resize mode for translating the coordinated
|
||||
* @param mirror @c true to mirror the image
|
||||
* @param scale_factor a multiplier for the width and height of the bitmap
|
||||
*/
|
||||
void gr_aabitmap(int x, int y, int resize_mode = GR_RESIZE_FULL, bool mirror = false, int scale = 100);
|
||||
void gr_aabitmap(int x, int y, int resize_mode = GR_RESIZE_FULL, bool mirror = false, float scale_factor = 1.0f);
|
||||
/**
|
||||
* @brief Draws a grey-scale bitmap multiplied with the current color
|
||||
* @param x The x-coordinate of the draw call
|
||||
|
||||
+57
-41
@@ -34,24 +34,20 @@ ShadowQuality Shadow_quality = ShadowQuality::Disabled;
|
||||
|
||||
bool Shadow_quality_uses_mod_option = false;
|
||||
|
||||
auto ShadowQualityOption =
|
||||
options::OptionBuilder<ShadowQuality>("Graphics.Shadows", "Shadow Quality", "The quality of the shadows")
|
||||
.values({{ShadowQuality::Disabled, "Disabled"},
|
||||
{ShadowQuality::Low, "Low"},
|
||||
{ShadowQuality::Medium, "Medium"},
|
||||
{ShadowQuality::High, "High"},
|
||||
{ShadowQuality::Ultra, "Ultra"}})
|
||||
.change_listener([](ShadowQuality val, bool initial) {
|
||||
if (initial) {
|
||||
Shadow_quality = val;
|
||||
}
|
||||
return initial; // No dynamic changes implemented
|
||||
})
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.category("Graphics")
|
||||
.default_val(ShadowQuality::Disabled)
|
||||
.importance(80)
|
||||
.finish();
|
||||
auto ShadowQualityOption = options::OptionBuilder<ShadowQuality>("Graphics.Shadows",
|
||||
std::pair<const char*, int>{"Shadow Quality", 1750},
|
||||
std::pair<const char*, int>{"The quality of the shadows", 1751})
|
||||
.values({{ShadowQuality::Disabled, {"Disabled", 1779}},
|
||||
{ShadowQuality::Low, {"Low", 1160}},
|
||||
{ShadowQuality::Medium, {"Medium", 1161}},
|
||||
{ShadowQuality::High, {"High", 1162}},
|
||||
{ShadowQuality::Ultra, {"Ultra", 1721}}})
|
||||
.change_listener([](ShadowQuality val, bool initial) {if (initial) {Shadow_quality = val;}return initial;})
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.category("Graphics")
|
||||
.default_val(ShadowQuality::Disabled)
|
||||
.importance(80)
|
||||
.finish();
|
||||
|
||||
bool shadows_obj_in_frustum(object *objp, matrix *light_orient, vec3d *min, vec3d *max)
|
||||
{
|
||||
@@ -222,14 +218,34 @@ void shadows_debug_show_frustum(matrix* orient, vec3d *pos, float fov, float asp
|
||||
g3_render_line_3d(true, &far_bottom_left, &far_top_left);
|
||||
}
|
||||
|
||||
void shadows_construct_light_frustum(light_frustum_info *shadow_data, matrix *light_matrix, matrix *orient, vec3d * /*pos*/, float fov, float aspect, float z_near, float z_far)
|
||||
void shadows_construct_light_frustum(light_frustum_info *shadow_data, matrix *light_matrix, matrix *orient, vec3d * /*pos*/, fov_t fov, float aspect, float z_near, float z_far)
|
||||
{
|
||||
// find the widths and heights of the near plane and far plane to determine the points of this frustum
|
||||
float near_height = tanf(fov * 0.5f) * z_near;
|
||||
float near_width = near_height * aspect;
|
||||
float near_l, near_r, near_u, near_d;
|
||||
float far_l, far_r, far_u, far_d;
|
||||
if (mpark::holds_alternative<float>(fov)) {
|
||||
near_d = tanf(mpark::get<float>(fov) * 0.5f) * z_near;
|
||||
near_u = -near_d;
|
||||
near_r = near_d * aspect;
|
||||
near_l = -near_r;
|
||||
|
||||
float far_height = tanf(fov * 0.5f) * z_far;
|
||||
float far_width = far_height * aspect;
|
||||
far_d = tanf(mpark::get<float>(fov) * 0.5f) * z_far;
|
||||
far_u = -far_d;
|
||||
far_r = far_d * aspect;
|
||||
far_l = -far_r;
|
||||
}
|
||||
else {
|
||||
const auto& afov = mpark::get<asymmetric_fov>(fov);
|
||||
near_d = tanf(-afov.down) * z_near;
|
||||
near_u = -tanf(afov.up) * z_near;
|
||||
near_r = tanf(-afov.left) * z_near;
|
||||
near_l = -tanf(afov.right) * z_near;
|
||||
|
||||
far_d = tanf(-afov.down) * z_far;
|
||||
far_u = -tanf(afov.up) * z_far;
|
||||
far_r = tanf(-afov.left) * z_far;
|
||||
far_l = -tanf(afov.right) * z_far;
|
||||
}
|
||||
|
||||
vec3d up_scale = ZERO_VECTOR;
|
||||
vec3d right_scale = ZERO_VECTOR;
|
||||
@@ -247,40 +263,40 @@ void shadows_construct_light_frustum(light_frustum_info *shadow_data, matrix *li
|
||||
|
||||
// near top left
|
||||
up_scale = orient->vec.uvec;
|
||||
vm_vec_scale(&up_scale, -near_height);
|
||||
vm_vec_scale(&up_scale, near_u);
|
||||
|
||||
right_scale = orient->vec.rvec;
|
||||
vm_vec_scale(&right_scale, -near_width);
|
||||
vm_vec_scale(&right_scale, near_l);
|
||||
|
||||
vm_vec_add(&near_top_left, &up_scale, &right_scale);
|
||||
vm_vec_add2(&near_top_left, &forward_scale_near);
|
||||
|
||||
// near top right
|
||||
up_scale = orient->vec.uvec;
|
||||
vm_vec_scale(&up_scale, -near_height);
|
||||
vm_vec_scale(&up_scale, near_u);
|
||||
|
||||
right_scale = orient->vec.rvec;
|
||||
vm_vec_scale(&right_scale, near_width);
|
||||
vm_vec_scale(&right_scale, near_r);
|
||||
|
||||
vm_vec_add(&near_top_right, &up_scale, &right_scale);
|
||||
vm_vec_add2(&near_top_right, &forward_scale_near);
|
||||
|
||||
// near bottom left
|
||||
up_scale = orient->vec.uvec;
|
||||
vm_vec_scale(&up_scale, near_height);
|
||||
vm_vec_scale(&up_scale, near_d);
|
||||
|
||||
right_scale = orient->vec.rvec;
|
||||
vm_vec_scale(&right_scale, -near_width);
|
||||
vm_vec_scale(&right_scale, near_l);
|
||||
|
||||
vm_vec_add(&near_bottom_left, &up_scale, &right_scale);
|
||||
vm_vec_add2(&near_bottom_left, &forward_scale_near);
|
||||
|
||||
// near bottom right
|
||||
up_scale = orient->vec.uvec;
|
||||
vm_vec_scale(&up_scale, near_height);
|
||||
vm_vec_scale(&up_scale, near_d);
|
||||
|
||||
right_scale = orient->vec.rvec;
|
||||
vm_vec_scale(&right_scale, near_width);
|
||||
vm_vec_scale(&right_scale, near_r);
|
||||
|
||||
vm_vec_add(&near_bottom_right, &up_scale, &right_scale);
|
||||
vm_vec_add2(&near_bottom_right, &forward_scale_near);
|
||||
@@ -292,40 +308,40 @@ void shadows_construct_light_frustum(light_frustum_info *shadow_data, matrix *li
|
||||
|
||||
// far top left
|
||||
up_scale = orient->vec.uvec;
|
||||
vm_vec_scale(&up_scale, -far_height);
|
||||
vm_vec_scale(&up_scale, far_u);
|
||||
|
||||
right_scale = orient->vec.rvec;
|
||||
vm_vec_scale(&right_scale, -far_width);
|
||||
vm_vec_scale(&right_scale, far_l);
|
||||
|
||||
vm_vec_add(&far_top_left, &up_scale, &right_scale);
|
||||
vm_vec_add2(&far_top_left, &forward_scale_far);
|
||||
|
||||
// far top right
|
||||
up_scale = orient->vec.uvec;
|
||||
vm_vec_scale(&up_scale, -far_height);
|
||||
vm_vec_scale(&up_scale, far_u);
|
||||
|
||||
right_scale = orient->vec.rvec;
|
||||
vm_vec_scale(&right_scale, far_width);
|
||||
vm_vec_scale(&right_scale, far_r);
|
||||
|
||||
vm_vec_add(&far_top_right, &up_scale, &right_scale);
|
||||
vm_vec_add2(&far_top_right, &forward_scale_far);
|
||||
|
||||
// far bottom left
|
||||
up_scale = orient->vec.uvec;
|
||||
vm_vec_scale(&up_scale, far_height);
|
||||
vm_vec_scale(&up_scale, far_d);
|
||||
|
||||
right_scale = orient->vec.rvec;
|
||||
vm_vec_scale(&right_scale, -far_width);
|
||||
vm_vec_scale(&right_scale, far_l);
|
||||
|
||||
vm_vec_add(&far_bottom_left, &up_scale, &right_scale);
|
||||
vm_vec_add2(&far_bottom_left, &forward_scale_far);
|
||||
|
||||
// far bottom right
|
||||
up_scale = orient->vec.uvec;
|
||||
vm_vec_scale(&up_scale, far_height);
|
||||
vm_vec_scale(&up_scale, far_d);
|
||||
|
||||
right_scale = orient->vec.rvec;
|
||||
vm_vec_scale(&right_scale, far_width);
|
||||
vm_vec_scale(&right_scale, far_r);
|
||||
|
||||
vm_vec_add(&far_bottom_right, &up_scale, &right_scale);
|
||||
vm_vec_add2(&far_bottom_right, &forward_scale_far);
|
||||
@@ -381,7 +397,7 @@ void shadows_construct_light_frustum(light_frustum_info *shadow_data, matrix *li
|
||||
shadows_construct_light_proj(shadow_data);
|
||||
}
|
||||
|
||||
matrix shadows_start_render(matrix *eye_orient, vec3d *eye_pos, float fov, float aspect, float veryneardist, float neardist, float middist, float fardist)
|
||||
matrix shadows_start_render(matrix *eye_orient, vec3d *eye_pos, fov_t fov, float aspect, float veryneardist, float neardist, float middist, float fardist)
|
||||
{
|
||||
if(Static_light.empty())
|
||||
return vmd_identity_matrix;
|
||||
@@ -419,7 +435,7 @@ void shadows_end_render()
|
||||
gr_shadow_map_end();
|
||||
}
|
||||
|
||||
void shadows_render_all(float fov, matrix *eye_orient, vec3d *eye_pos)
|
||||
void shadows_render_all(fov_t fov, matrix *eye_orient, vec3d *eye_pos)
|
||||
{
|
||||
if (gr_screen.mode == GR_STUB) {
|
||||
return;
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "object/object.h"
|
||||
#include "render/3d.h"
|
||||
|
||||
#define MAX_SHADOW_CASCADES 4
|
||||
|
||||
@@ -38,11 +39,11 @@ extern bool Shadow_quality_uses_mod_option;
|
||||
extern matrix4 Shadow_proj_matrix[MAX_SHADOW_CASCADES];
|
||||
extern float Shadow_cascade_distances[MAX_SHADOW_CASCADES];
|
||||
|
||||
void shadows_construct_light_frustum(vec3d *min_out, vec3d *max_out, vec3d light_vec, matrix *orient, vec3d *pos, float fov, float aspect, float z_near, float z_far);
|
||||
void shadows_construct_light_frustum(vec3d *min_out, vec3d *max_out, vec3d light_vec, matrix *orient, vec3d *pos, fov_t fov, float aspect, float z_near, float z_far);
|
||||
bool shadows_obj_in_frustum(object *objp, vec3d *min, vec3d *max, matrix *light_orient);
|
||||
void shadows_render_all(float fov, matrix *eye_orient, vec3d *eye_pos);
|
||||
void shadows_render_all(fov_t fov, matrix *eye_orient, vec3d *eye_pos);
|
||||
|
||||
matrix shadows_start_render(matrix *eye_orient, vec3d *eye_pos, float fov, float aspect, float veryneardist, float neardist, float middist, float fardist);
|
||||
matrix shadows_start_render(matrix *eye_orient, vec3d *eye_pos, fov_t fov, float aspect, float veryneardist, float neardist, float middist, float fardist);
|
||||
void shadows_end_render();
|
||||
|
||||
/**
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace font
|
||||
{
|
||||
if (string[i] >= Lcl_special_chars || string[i] < 0)
|
||||
{
|
||||
// Special character needs to be handled seperately
|
||||
// Special character needs to be handled separately
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,8 +30,9 @@ struct deferred_global_data {
|
||||
|
||||
float invScreenWidth;
|
||||
float invScreenHeight;
|
||||
float nearPlane;
|
||||
|
||||
float pad[2];
|
||||
float pad;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -321,6 +321,9 @@ bool VulkanRenderer::initDisplayDevice() const
|
||||
}
|
||||
}
|
||||
|
||||
if (Cmdline_capture_mouse)
|
||||
attrs.flags.set(os::ViewPortFlags::Capture_Mouse);
|
||||
|
||||
auto viewPort = m_graphicsOps->createViewport(attrs);
|
||||
if (!viewPort) {
|
||||
return false;
|
||||
|
||||
+35
-68
@@ -71,7 +71,7 @@ SCP_vector<std::unique_ptr<HudGauge>> default_hud_gauges;
|
||||
#define HUD_NEW_ALPHA_BRIGHT_HI 255
|
||||
|
||||
// Externals not related to the HUD code itself
|
||||
extern float View_zoom;
|
||||
extern fov_t View_zoom;
|
||||
|
||||
// globals that will control the color of the HUD gauges
|
||||
int HUD_color_red = 0;
|
||||
@@ -91,10 +91,6 @@ color HUD_color_debug; // grey debug text shown on HUD
|
||||
|
||||
static sound_handle Player_engine_snd_loop = sound_handle::invalid();
|
||||
|
||||
// HUD render frame offsets
|
||||
float HUD_offset_x = 0.0f;
|
||||
float HUD_offset_y = 0.0f;
|
||||
|
||||
// the offset of the player's view vector and the ship forward vector in pixels (Swifty)
|
||||
int HUD_nose_x;
|
||||
int HUD_nose_y;
|
||||
@@ -1033,8 +1029,8 @@ void HudGauge::renderCircle(int x, int y, int diameter, bool filled)
|
||||
|
||||
void HudGauge::setClip(int x, int y, int w, int h)
|
||||
{
|
||||
int hx = fl2i(HUD_offset_x);
|
||||
int hy = fl2i(HUD_offset_y);
|
||||
int hx = 0;
|
||||
int hy = 0;
|
||||
|
||||
if ( gr_screen.rendering_to_texture != -1 ) {
|
||||
gr_set_screen_scale(canvas_w, canvas_h, -1, -1, target_w, target_h, target_w, target_h, true);
|
||||
@@ -1051,17 +1047,22 @@ void HudGauge::setClip(int x, int y, int w, int h)
|
||||
|
||||
gr_set_clip(hx, hy, w, h);
|
||||
} else {
|
||||
if ( reticle_follow ) {
|
||||
if (reticle_follow) {
|
||||
hx += HUD_nose_x;
|
||||
hy += HUD_nose_y;
|
||||
|
||||
gr_resize_screen_pos(&hx, &hy);
|
||||
gr_set_screen_scale(base_w, base_h);
|
||||
gr_unsize_screen_pos(&hx, &hy);
|
||||
}
|
||||
else {
|
||||
gr_set_screen_scale(base_w, base_h);
|
||||
}
|
||||
|
||||
gr_resize_screen_pos(&hx, &hy);
|
||||
|
||||
gr_set_screen_scale(base_w, base_h);
|
||||
x += hx;
|
||||
y += hy;
|
||||
gr_resize_screen_pos(&x, &y, &w, &h);
|
||||
|
||||
gr_set_clip(hx+x, hy+y, w, h, GR_RESIZE_NONE);
|
||||
gr_set_clip(x, y, w, h, GR_RESIZE_NONE);
|
||||
}
|
||||
|
||||
gr_reset_screen_scale();
|
||||
@@ -1085,9 +1086,6 @@ void HudGauge::resetClip()
|
||||
|
||||
gr_set_clip(hx, hy, w, h);
|
||||
} else {
|
||||
hx = fl2i(HUD_offset_x);
|
||||
hy = fl2i(HUD_offset_y);
|
||||
|
||||
gr_resize_screen_pos(&hx, &hy);
|
||||
gr_set_screen_scale(base_w, base_h);
|
||||
|
||||
@@ -1778,8 +1776,8 @@ void HudGaugeMissionTime::render(float /*frametime*/)
|
||||
int minutes=0;
|
||||
int seconds=0;
|
||||
|
||||
mission_time = f2fl(Missiontime); // convert to seconds
|
||||
|
||||
mission_time = f2fl(Missiontime) + (float)The_mission.HUD_timer_padding; // convert to seconds
|
||||
|
||||
minutes=(int)(mission_time/60);
|
||||
seconds=(int)mission_time%60;
|
||||
|
||||
@@ -2021,7 +2019,7 @@ void hud_damage_popup_init()
|
||||
Damage_flash_timer = 1;
|
||||
|
||||
for ( i = 0; i < SUBSYSTEM_MAX; i++ ) {
|
||||
Pl_hud_subsys_info[i].last_str = 1000.0f;
|
||||
Pl_hud_subsys_info[i].last_str = 1.0f;
|
||||
Pl_hud_subsys_info[i].flash_duration_timestamp = 1;
|
||||
Pl_hud_next_flash_timestamp = 1;
|
||||
Pl_hud_is_bright = 0;
|
||||
@@ -2076,6 +2074,11 @@ void HudGaugeDamage::initLineHeight(int h)
|
||||
line_h = h;
|
||||
}
|
||||
|
||||
void HudGaugeDamage::initDisplayValue(bool value)
|
||||
{
|
||||
always_display = value;
|
||||
}
|
||||
|
||||
void HudGaugeDamage::initBitmaps(const char *fname_top, const char *fname_middle, const char *fname_bottom)
|
||||
{
|
||||
damage_top.first_frame = bm_load_animation(fname_top, &damage_top.num_frames);
|
||||
@@ -2136,7 +2139,7 @@ void HudGaugeDamage::render(float /*frametime*/)
|
||||
for ( pss = GET_FIRST(&Player_ship->subsys_list); pss !=END_OF_LIST(&Player_ship->subsys_list); pss = GET_NEXT(pss) ) {
|
||||
psub = pss->system_info;
|
||||
strength = ship_get_subsystem_strength(Player_ship, psub->type);
|
||||
if ( strength < 1 ) {
|
||||
if ( always_display || strength < 1 ) {
|
||||
// display the actual health of this specific subsystem --wookieejedi
|
||||
if (pss->max_hits > 0) {
|
||||
// get percentage if this subsystem has hitpoints to begin with
|
||||
@@ -2273,7 +2276,7 @@ void HudGaugeDamage::render(float /*frametime*/)
|
||||
// Show hull integrity if it's below 100% or if a subsystem is damaged
|
||||
// The second case is just to make the display look complete
|
||||
// The third case is there to make the gauge appear only if needed if the right option is set
|
||||
if ( screen_integrity < 100 || !info_lines.empty() ) {
|
||||
if ( always_display || screen_integrity < 100 || !info_lines.empty() ) {
|
||||
DamageInfo info;
|
||||
|
||||
info.name = XSTR( "Hull Integrity", 220);
|
||||
@@ -2407,10 +2410,11 @@ int hud_anim_load(hud_anim *ha)
|
||||
* @param reverse Play animation in reverse (default 0)
|
||||
* @param resize_mode Resize for non-standard resolutions
|
||||
* @param mirror Mirror along y-axis so icon points left instead of right
|
||||
* @param scale_factor Multiplier for the width and height
|
||||
*
|
||||
* @returns 1 on success, 0 on failure
|
||||
*/
|
||||
int hud_anim_render(hud_anim *ha, float frametime, int draw_alpha, int loop, int hold_last, int reverse, int resize_mode, bool mirror)
|
||||
int hud_anim_render(hud_anim *ha, float frametime, int draw_alpha, int loop, int hold_last, int reverse, int resize_mode, bool mirror, float scale_factor)
|
||||
{
|
||||
int framenum;
|
||||
|
||||
@@ -2434,7 +2438,7 @@ int hud_anim_render(hud_anim *ha, float frametime, int draw_alpha, int loop, int
|
||||
if(emp_should_blit_gauge()){
|
||||
gr_set_bitmap(ha->first_frame + framenum);
|
||||
if ( draw_alpha ){
|
||||
gr_aabitmap(ha->sx, ha->sy, resize_mode, mirror);
|
||||
gr_aabitmap(ha->sx, ha->sy, resize_mode, mirror, scale_factor);
|
||||
} else {
|
||||
gr_bitmap(ha->sx, ha->sy, resize_mode);
|
||||
}
|
||||
@@ -2961,6 +2965,9 @@ void HudGaugeSupport::render(float /*frametime*/)
|
||||
int show_time, w, h;
|
||||
char outstr[64];
|
||||
|
||||
if (background.first_frame < 0)
|
||||
return;
|
||||
|
||||
if ( !Hud_support_view_active ) {
|
||||
return;
|
||||
}
|
||||
@@ -3742,42 +3749,8 @@ int hud_objective_notify_active()
|
||||
* @param wiggedy_wack
|
||||
* @param eye_orient
|
||||
*/
|
||||
void HUD_set_offsets(object *viewer_obj, int wiggedy_wack, matrix *eye_orient)
|
||||
void HUD_set_offsets()
|
||||
{
|
||||
if ( (viewer_obj == Player_obj) && wiggedy_wack ){
|
||||
vec3d tmp;
|
||||
vertex pt;
|
||||
|
||||
HUD_offset_x = 0.0f;
|
||||
HUD_offset_y = 0.0f;
|
||||
|
||||
vm_vec_scale_add( &tmp, &Eye_position, &eye_orient->vec.fvec, 100.0f );
|
||||
|
||||
(void) g3_rotate_vertex(&pt,&tmp);
|
||||
|
||||
g3_project_vertex(&pt);
|
||||
|
||||
gr_unsize_screen_posf( &pt.screen.xyw.x, &pt.screen.xyw.y );
|
||||
HUD_offset_x -= 0.45f * (i2fl(gr_screen.clip_width_unscaled)*0.5f - pt.screen.xyw.x);
|
||||
HUD_offset_y -= 0.45f * (i2fl(gr_screen.clip_height_unscaled)*0.5f - pt.screen.xyw.y);
|
||||
|
||||
if ( HUD_offset_x > 100.0f ) {
|
||||
HUD_offset_x = 100.0f;
|
||||
} else if ( HUD_offset_x < -100.0f ) {
|
||||
HUD_offset_x += 100.0f;
|
||||
}
|
||||
|
||||
if ( HUD_offset_y > 100.0f ) {
|
||||
HUD_offset_y = 100.0f;
|
||||
} else if ( HUD_offset_y < -100.0f ) {
|
||||
HUD_offset_y += 100.0f;
|
||||
}
|
||||
|
||||
} else {
|
||||
HUD_offset_x = 0.0f;
|
||||
HUD_offset_y = 0.0f;
|
||||
}
|
||||
|
||||
if ( Viewer_mode & ( VM_TOPDOWN | VM_CHASE ) ) {
|
||||
HUD_nose_x = 0;
|
||||
HUD_nose_y = 0;
|
||||
@@ -3841,10 +3814,7 @@ void HUD_get_nose_coordinates(int *x, int *y)
|
||||
*/
|
||||
void HUD_reset_clip()
|
||||
{
|
||||
int hx = fl2i(HUD_offset_x);
|
||||
int hy = fl2i(HUD_offset_y);
|
||||
|
||||
gr_set_clip(hx, hy, gr_screen.max_w_unscaled, gr_screen.max_h_unscaled);
|
||||
gr_set_clip(0, 0, gr_screen.max_w_unscaled, gr_screen.max_h_unscaled);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3852,10 +3822,7 @@ void HUD_reset_clip()
|
||||
*/
|
||||
void HUD_set_clip(int x, int y, int w, int h)
|
||||
{
|
||||
int hx = fl2i(HUD_offset_x);
|
||||
int hy = fl2i(HUD_offset_y);
|
||||
|
||||
gr_set_clip(hx+x, hy+y, w, h);
|
||||
gr_set_clip(x, y, w, h);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3865,7 +3832,7 @@ void HUD_set_clip(int x, int y, int w, int h)
|
||||
void hud_save_restore_camera_data(int save)
|
||||
{
|
||||
static vec3d save_view_position;
|
||||
static float save_view_zoom;
|
||||
static fov_t save_view_zoom;
|
||||
static matrix save_view_matrix;
|
||||
static matrix save_eye_matrix;
|
||||
static vec3d save_eye_position;
|
||||
@@ -4131,7 +4098,7 @@ void HudGaugeSupernova::render(float /*frametime*/)
|
||||
}
|
||||
|
||||
HudGaugeFlightPath::HudGaugeFlightPath():
|
||||
HudGauge(HUD_OBJECT_FLIGHT_PATH, HUD_CENTER_RETICLE, false, false, VM_EXTERNAL | VM_DEAD_VIEW | VM_WARP_CHASE | VM_PADLOCK_ANY, 255, 255, 255)
|
||||
HudGauge3DAnchor(HUD_OBJECT_FLIGHT_PATH, HUD_CENTER_RETICLE, false, false, VM_EXTERNAL | VM_DEAD_VIEW | VM_WARP_CHASE | VM_PADLOCK_ANY, 255, 255, 255)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
+24
-5
@@ -129,7 +129,7 @@ void hud_render_gauges(int cockpit_display_num = -1);
|
||||
void hud_stop_looped_engine_sounds();
|
||||
|
||||
// set the offset values for this render frame
|
||||
void HUD_set_offsets(object *viewer_obj, int wiggedy_wack, matrix *eye_orient);
|
||||
void HUD_set_offsets();
|
||||
// returns the offset between the player's view vector and the forward vector of the ship in pixels (Swifty)
|
||||
void HUD_get_nose_coordinates(int *x, int *y);
|
||||
|
||||
@@ -149,7 +149,7 @@ void hud_num_make_mono(char *num_str, int font_num = font::FONT1);
|
||||
// functions for handling hud animations
|
||||
void hud_anim_init(hud_anim *ha, int sx, int sy, const char *filename);
|
||||
void hud_frames_init(hud_frames *hf);
|
||||
int hud_anim_render(hud_anim *ha, float frametime, int draw_alpha=0, int loop=1, int hold_last=0, int reverse=0,int resize_mode=GR_RESIZE_FULL, bool mirror = false);
|
||||
int hud_anim_render(hud_anim *ha, float frametime, int draw_alpha=0, int loop=1, int hold_last=0, int reverse=0,int resize_mode=GR_RESIZE_FULL, bool mirror = false, float scale_factor = 1.0f);
|
||||
int hud_anim_load(hud_anim *ha);
|
||||
|
||||
// functions for displaying the support view popup
|
||||
@@ -277,7 +277,7 @@ public:
|
||||
void initOriginAndOffset(float originX, float originY, int offsetX, int offsetY);
|
||||
void initCoords(bool use_coords, int coordsX, int coordsY);
|
||||
|
||||
void initSlew(bool slew);
|
||||
virtual void initSlew(bool slew);
|
||||
void initCockpitTarget(const char* display_name, int _target_x, int _target_y, int _target_w, int _target_h, int _canvas_w, int _canvas_h);
|
||||
void initRenderStatus(bool render);
|
||||
|
||||
@@ -362,6 +362,21 @@ public:
|
||||
void resetClip();
|
||||
};
|
||||
|
||||
//Use this instead of HudGauge whenever you have a HudGauge that is anchored in 3D-space (i.e. takes its rendering coordinates from g3_rotate/project_vertex, as these MUST NEVER slew.
|
||||
class HudGauge3DAnchor : public HudGauge {
|
||||
|
||||
public:
|
||||
HudGauge3DAnchor()
|
||||
: HudGauge() { }
|
||||
HudGauge3DAnchor(int _gauge_object, int _gauge_config, bool /*_slew*/, bool _message, int _disabled_views, int r, int g, int b)
|
||||
: HudGauge(_gauge_object, _gauge_config, false, _message, _disabled_views, r, g, b) { }
|
||||
// constructor for custom gauges
|
||||
HudGauge3DAnchor(int _gauge_config, bool /*_slew*/, int r, int g, int b, char* _custom_name, char* _custom_text, char* frame_fname, int txtoffset_x, int txtoffset_y)
|
||||
: HudGauge(_gauge_config, false, r, g, b, _custom_name, _custom_text, frame_fname, txtoffset_x, txtoffset_y) { }
|
||||
|
||||
void initSlew(bool /*slew*/) override {};
|
||||
};
|
||||
|
||||
class HudGaugeMissionTime: public HudGauge // HUD_MISSION_TIME
|
||||
{
|
||||
hud_frames time_gauge;
|
||||
@@ -492,7 +507,10 @@ protected:
|
||||
|
||||
int next_flash;
|
||||
bool flash_status;
|
||||
public:
|
||||
|
||||
bool always_display;
|
||||
|
||||
public:
|
||||
HudGaugeDamage();
|
||||
void initBitmaps(const char *fname_top, const char *fname_middle, const char *fname_bottom);
|
||||
void initHeaderOffsets(int x, int y);
|
||||
@@ -503,6 +521,7 @@ public:
|
||||
void initSubsysIntegValueOffsetX(int x);
|
||||
void initBottomBgOffset(int offset);
|
||||
void initLineHeight(int h);
|
||||
void initDisplayValue(bool value);
|
||||
void render(float frametime) override;
|
||||
void pageIn() override;
|
||||
void initialize() override;
|
||||
@@ -562,7 +581,7 @@ public:
|
||||
void render(float frametime) override;
|
||||
};
|
||||
|
||||
class HudGaugeFlightPath: public HudGauge
|
||||
class HudGaugeFlightPath: public HudGauge3DAnchor
|
||||
{
|
||||
hud_frames Marker;
|
||||
|
||||
|
||||
@@ -331,7 +331,7 @@ int draw_subsys_brackets(graphics::line_draw_list* draw_list, ship_subsys* subsy
|
||||
}
|
||||
|
||||
HudGaugeBrackets::HudGaugeBrackets():
|
||||
HudGauge(HUD_OBJECT_BRACKETS, HUD_OFFSCREEN_INDICATOR, false, true, VM_DEAD_VIEW, 255, 255, 255)
|
||||
HudGauge3DAnchor(HUD_OBJECT_BRACKETS, HUD_OFFSCREEN_INDICATOR, false, true, VM_DEAD_VIEW, 255, 255, 255)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ void draw_brackets_diamond_quick(graphics::line_draw_list* draw_list, int x1, in
|
||||
|
||||
int draw_subsys_brackets(graphics::line_draw_list* draw_list, ship_subsys* subsys, int min_width, int min_height, bool draw = true, bool set_color = true, int* draw_coords = NULL);
|
||||
|
||||
class HudGaugeBrackets: public HudGauge
|
||||
class HudGaugeBrackets: public HudGauge3DAnchor
|
||||
{
|
||||
protected:
|
||||
int attacking_dot;
|
||||
|
||||
@@ -900,7 +900,7 @@ void hud_config_render_gauges(bool API_Access)
|
||||
resize = GR_RESIZE_NONE;
|
||||
}
|
||||
|
||||
gr_aabitmap(HC_gauge_coords[i].x, HC_gauge_coords[i].y, resize, false, (int)(HC_gauge_scale * 100));
|
||||
gr_aabitmap(HC_gauge_coords[i].x, HC_gauge_coords[i].y, resize, false, HC_gauge_scale);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1266,7 +1266,7 @@ void hud_config_button_do(int n)
|
||||
|
||||
case HCB_SAVE_HCF:
|
||||
int exists;
|
||||
char *out;
|
||||
const char *out;
|
||||
|
||||
// get the text in the input control
|
||||
exists = 0;
|
||||
@@ -1658,10 +1658,6 @@ void hud_config_as_observer(ship *shipp,ai_info *aif)
|
||||
// store the current hud
|
||||
hud_config_backup();
|
||||
|
||||
// bash these values so the HUD is not offset incorrectly
|
||||
HUD_offset_x = 0.0f;
|
||||
HUD_offset_y = 0.0f;
|
||||
|
||||
// initialize the observer HUD
|
||||
hud_observer_init(shipp,aif);
|
||||
}
|
||||
@@ -1708,10 +1704,9 @@ void hud_config_color_load(const char *name)
|
||||
{
|
||||
int idx;
|
||||
char str[1024];
|
||||
char *fname;
|
||||
ubyte r, g, b, a;
|
||||
|
||||
fname = cf_add_ext(name, ".hcf");
|
||||
const char *fname = cf_add_ext(name, ".hcf");
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
+19
-22
@@ -238,6 +238,9 @@ void HudGaugeEscort::render(float /*frametime*/)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (Escort_gauges[0].first_frame < 0)
|
||||
return;
|
||||
|
||||
if ( !Show_escort_view ) {
|
||||
return;
|
||||
}
|
||||
@@ -297,7 +300,6 @@ void HudGaugeEscort::renderIcon(int x, int y, int index)
|
||||
float shields, integrity;
|
||||
int screen_integrity, offset, objnum = -1;
|
||||
char buf[255];
|
||||
const player *pl = nullptr;
|
||||
|
||||
auto eship = get_escort_entry_from_index(index);
|
||||
|
||||
@@ -309,8 +311,7 @@ void HudGaugeEscort::renderIcon(int x, int y, int index)
|
||||
int np_index = find_player_index(eship->np_id);
|
||||
|
||||
if (np_index >= 0) {
|
||||
pl = Net_players[np_index].m_player;
|
||||
objnum = pl->objnum;
|
||||
objnum = Net_players[np_index].m_player->objnum;
|
||||
|
||||
// this can occassionally happen in multi when a player still needs to respawn.
|
||||
if (objnum < 0 || Objects[objnum].type != OBJ_SHIP){
|
||||
@@ -347,15 +348,9 @@ void HudGaugeEscort::renderIcon(int x, int y, int index)
|
||||
}
|
||||
|
||||
// print out ship name
|
||||
// behavior largely taken from message_queue_process() in missionmessage.cpp,
|
||||
// but with the multiplayer callsign behavior kept in accordance with #1674.
|
||||
if (sp->callsign_index >= 0 && !pl)
|
||||
{
|
||||
// Without the !pl, this would just stuff short_callsign anyway, so may
|
||||
// as well use the ship name and append it instead.
|
||||
hud_stuff_ship_callsign(buf, sp);
|
||||
}
|
||||
else if (((Iff_info[sp->team].flags & IFFF_WING_NAME_HIDDEN) && (sp->wingnum != -1)) || (sp->flags[Ship::Ship_Flags::Hide_ship_name]))
|
||||
// original behavior replaced with similar logic to hudtargetbox.cpp, except
|
||||
// if the name is hidden, it's replaced with the class name.
|
||||
if (((Iff_info[sp->team].flags & IFFF_WING_NAME_HIDDEN) && (sp->wingnum != -1)) || (sp->flags[Ship::Ship_Flags::Hide_ship_name]))
|
||||
{
|
||||
// If we're hiding the ship name, we probably shouldn't append the callsign either
|
||||
hud_stuff_ship_class(buf, sp);
|
||||
@@ -364,17 +359,19 @@ void HudGaugeEscort::renderIcon(int x, int y, int index)
|
||||
{
|
||||
hud_stuff_ship_name(buf, sp);
|
||||
|
||||
// maybe add callsign if multi and player ship
|
||||
if (pl) {
|
||||
SCP_string callsign;
|
||||
// maybe concatenate the callsign
|
||||
if (*buf)
|
||||
{
|
||||
char callsign[NAME_LENGTH];
|
||||
|
||||
callsign.reserve(32);
|
||||
|
||||
callsign += " (";
|
||||
callsign += pl->short_callsign;
|
||||
callsign += ")";
|
||||
|
||||
strcat_s(buf, callsign.c_str());
|
||||
hud_stuff_ship_callsign(callsign, sp);
|
||||
if (*callsign)
|
||||
sprintf(&buf[strlen(buf)], " (%s)", callsign);
|
||||
}
|
||||
// maybe substitute the callsign
|
||||
else
|
||||
{
|
||||
hud_stuff_ship_callsign(buf, sp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+17
-7
@@ -125,19 +125,25 @@ void update_ets(object* objp, float fl_frametime)
|
||||
// This will translate to 71% max speed at 50% engines, and 31% max speed at 10% engines
|
||||
//
|
||||
|
||||
float eng_current_strength = ship_get_subsystem_strength(ship_p, SUBSYSTEM_ENGINE);
|
||||
float engine_aggregate_strength;
|
||||
if (ship_p->flags[Ship::Ship_Flags::Maneuver_despite_engines]) {
|
||||
// Pretend our strength is 100% when this flag is active
|
||||
engine_aggregate_strength = 1.0f;
|
||||
} else {
|
||||
engine_aggregate_strength = ship_get_subsystem_strength(ship_p, SUBSYSTEM_ENGINE);
|
||||
}
|
||||
|
||||
// only update max speed if aggregate engine health has changed
|
||||
// which helps minimze amount of overrides to max speed
|
||||
if (eng_current_strength != ship_p->prev_engine_aggregate_strength) {
|
||||
// only update max speed if engine_aggregate_strength has changed
|
||||
// which helps minimize amount of overrides to max speed
|
||||
if (engine_aggregate_strength != ship_p->prev_engine_aggregate_strength) {
|
||||
ets_update_max_speed(objp);
|
||||
ship_p->prev_engine_aggregate_strength = eng_current_strength;
|
||||
ship_p->prev_engine_aggregate_strength = engine_aggregate_strength;
|
||||
|
||||
// check if newly updated max speed should be reduced due to engine damage
|
||||
// don't let engine strength affect max speed when playing on lowest skill level
|
||||
if ((objp != Player_obj) || (Game_skill_level > 0)) {
|
||||
if (eng_current_strength < SHIP_MIN_ENGINES_FOR_FULL_SPEED) {
|
||||
objp->phys_info.max_vel.xyz.z *= fl_sqrt(eng_current_strength);
|
||||
if (engine_aggregate_strength < SHIP_MIN_ENGINES_FOR_FULL_SPEED) {
|
||||
objp->phys_info.max_vel.xyz.z *= fl_sqrt(engine_aggregate_strength);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -888,6 +894,10 @@ void HudGaugeEts::pageIn()
|
||||
*/
|
||||
void HudGaugeEts::blitGauge(int index)
|
||||
{
|
||||
if (Ets_bar.first_frame < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int y_start, y_end, clip_h, w, h, x, y;
|
||||
|
||||
clip_h = fl2i( (1 - Energy_levels[index]) * ETS_bar_h );
|
||||
|
||||
Loaded 100 of 329 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user