Merge branch 'stable' into unit-tests

This commit is contained in:
Mia McMahill 2025-12-27 16:31:52 -06:00
commit 8a0af04eae
434 changed files with 16669 additions and 18019 deletions

15
.github/FUNDING.yml vendored Normal file
View file

@ -0,0 +1,15 @@
# These are supported funding model platforms
github: odamex
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
polar: # Replace with a single Polar username
buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
thanks_dev: # Replace with a single thanks.dev username
custom: ['https://odamex.net'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

View file

@ -0,0 +1,79 @@
name: Update Prerelease
inputs:
files:
description: "Files to upload to release artifacts"
required: true
build_number:
description: "Prerelease build number"
required: true
new_version:
description: "Version number of the upcoming release"
required: true
runs:
using: "composite"
steps:
- name: Check if prerelease is outdated
id: check
shell: bash
run: |
if git fetch --quiet origin refs/tags/prerelease:refs/tags/prerelease; then
TAG_COMMIT=$(git rev-list -n 1 refs/tags/prerelease)
if [ "$TAG_COMMIT" != "${{ github.sha }}" ]; then
echo "should_delete=true" >> "$GITHUB_OUTPUT"
else
echo "should_delete=false" >> "$GITHUB_OUTPUT"
fi
else
echo "should_delete=false" >> "$GITHUB_OUTPUT"
fi
- name: Delete old prerelease
if: steps.check.outputs.should_delete == 'true'
shell: bash
env:
GH_TOKEN: ${{ github.token }}
run: |
gh release delete prerelease --yes || true
git push origin :prerelease || true
- name: Find last release tag
id: get_tag
shell: bash
run: |
latest_tag=$(git tag -l --sort=version:refname "[0-9]*.[0-9]*.[0-9]*" | tail -n 1)
echo "latest_tag=$latest_tag" >> $GITHUB_OUTPUT
- name: Create prerelease
uses: softprops/action-gh-release@v2.3.4
id: create_prerelease
with:
tag_name: prerelease
target_commitish: ${{ github.sha }}
name: "Odamex ${{ inputs.new_version }} Prerelease ${{ inputs.build_number }}"
prerelease: true
make_latest: false
draft: false
overwrite_files: true
generate_release_notes: false
body: ""
files: ${{ inputs.files }}
- name: Generate release notes
id: build_changelog
uses: actions/github-script@v8
env:
latest_tag: ${{ steps.get_tag.outputs.latest_tag }}
release_id: ${{ steps.create_prerelease.outputs.id }}
with:
script: |
const notes = await github.rest.repos.generateReleaseNotes({
owner: context.repo.owner,
repo: context.repo.repo,
tag_name: "prerelease",
previous_tag_name: process.env.latest_tag,
});
await github.rest.repos.updateRelease({
owner: context.repo.owner,
repo: context.repo.repo,
release_id: process.env.release_id,
body: notes.data.body,
});

View file

@ -5,6 +5,9 @@ on:
branches:
- 'release/[0-9]+.[0-9]+.[0-9]+' # Only run on major.minor.patch releases
permissions:
contents: write
jobs:
pre_job:
name: Build Preparation
@ -21,12 +24,12 @@ jobs:
persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal token
fetch-depth: 0 # Required due to the way Git works, without it this action won't be able to find any or the correct tags
- name: Install GitVersion
uses: gittools/actions/gitversion/setup@v0.9.7
uses: gittools/actions/gitversion/setup@v4.1.0
with:
versionSpec: '5.x'
versionSpec: '6.x'
- name: Determine Version
id: gitversion
uses: gittools/actions/gitversion/execute@v0.9.7
uses: gittools/actions/gitversion/execute@v4.1.0
- name: Get Commits From Source
id: revlist
shell: bash
@ -44,12 +47,9 @@ jobs:
echo "PreReleaseNumber: ${{ steps.gitversion.outputs.preReleaseNumber }}"
echo "WeightedPreReleaseNumber: ${{ steps.gitversion.outputs.weightedPreReleaseNumber }}"
echo "BuildMetaData: ${{ steps.gitversion.outputs.buildMetaData }}"
echo "BuildMetaDataPadded: ${{ steps.gitversion.outputs.buildMetaDataPadded }}"
echo "FullBuildMetaData: ${{ steps.gitversion.outputs.fullBuildMetaData }}"
echo "MajorMinorPatch: ${{ steps.gitversion.outputs.majorMinorPatch }}"
echo "SemVer: ${{ steps.gitversion.outputs.semVer }}"
echo "LegacySemVer: ${{ steps.gitversion.outputs.legacySemVer }}"
echo "LegacySemVerPadded: ${{ steps.gitversion.outputs.legacySemVerPadded }}"
echo "AssemblySemVer: ${{ steps.gitversion.outputs.assemblySemVer }}"
echo "AssemblySemFileVer: ${{ steps.gitversion.outputs.assemblySemFileVer }}"
echo "FullSemVer: ${{ steps.gitversion.outputs.fullSemVer }}"
@ -58,13 +58,8 @@ jobs:
echo "EscapedBranchName: ${{ steps.gitversion.outputs.escapedBranchName }}"
echo "Sha: ${{ steps.gitversion.outputs.sha }}"
echo "ShortSha: ${{ steps.gitversion.outputs.shortSha }}"
echo "NuGetVersionV2: ${{ steps.gitversion.outputs.nuGetVersionV2 }}"
echo "NuGetVersion: ${{ steps.gitversion.outputs.nuGetVersion }}"
echo "NuGetPreReleaseTagV2: ${{ steps.gitversion.outputs.nuGetPreReleaseTagV2 }}"
echo "NuGetPreReleaseTag: ${{ steps.gitversion.outputs.nuGetPreReleaseTag }}"
echo "VersionSourceSha: ${{ steps.gitversion.outputs.versionSourceSha }}"
echo "CommitsSinceVersionSource: ${{ steps.gitversion.outputs.commitsSinceVersionSource }}"
echo "CommitsSinceVersionSourcePadded: ${{ steps.gitversion.outputs.commitsSinceVersionSourcePadded }}"
echo "UncommittedChanges: ${{ steps.gitversion.outputs.uncommittedChanges }}"
echo "CommitDate: ${{ steps.gitversion.outputs.commitDate }}"
echo "TotalCommits: ${{ steps.revlist.outputs.totalCommits }}"
@ -212,13 +207,13 @@ jobs:
--default-branch=${{ env.MODIFIED_BRANCH_NAME }} -v
- name: Pack flatpak
run: |
flatpak build-bundle repo odamex.flatpak net.odamex.Odamex ${{ env.MODIFIED_BRANCH_NAME }} \
--runtime-repo=https://flathub.org/repo/flathub.flatpakrepo
flatpak build-bundle repo odamex-linux-x86_64-${{env.new_version}}-prerelease.${{ env.build_number }}.flatpak \
net.odamex.Odamex ${{ env.MODIFIED_BRANCH_NAME }} --runtime-repo=https://flathub.org/repo/flathub.flatpakrepo
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: Odamex-Flatpak-x86_64
path: odamex.flatpak
path: odamex-linux-x86_64-${{env.new_version}}-prerelease.${{ env.build_number }}.flatpak
build-flatpak-arm:
name: Build Flatpak (Ubuntu 24.04 ARM)
needs: pre_job
@ -261,10 +256,39 @@ jobs:
--default-branch=${{ env.MODIFIED_BRANCH_NAME }} -v
- name: Pack flatpak
run: |
flatpak build-bundle repo odamex.flatpak net.odamex.Odamex ${{ env.MODIFIED_BRANCH_NAME }} \
--runtime-repo=https://flathub.org/repo/flathub.flatpakrepo
flatpak build-bundle repo odamex-linux-arm64-${{env.new_version}}-prerelease.${{ env.build_number }}.flatpak \
net.odamex.Odamex ${{ env.MODIFIED_BRANCH_NAME }} --runtime-repo=https://flathub.org/repo/flathub.flatpakrepo
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: Odamex-Flatpak-ARM64
path: odamex.flatpak
path: odamex-linux-arm64-${{env.new_version}}-prerelease.${{ env.build_number }}.flatpak
package-and-upload:
name: Package and Upload Artifacts
runs-on: windows-latest
needs: [pre_job, build-flatpak, build-flatpak-arm]
env:
build_number: ${{ needs.pre_job.outputs.build_number }}
new_version: ${{ needs.pre_job.outputs.new_version }}
steps:
- uses: actions/checkout@v4
with:
fetch-tags: true
- name: Download x86_64 Flatpak
uses: actions/download-artifact@v4
with:
name: Odamex-Flatpak-x86_64
- name: Download Arm Flatpak
uses: actions/download-artifact@v4
with:
name: Odamex-Flatpak-ARM64
- name: Create or update prerelease
uses: ./.github/actions/update-prerelease
env:
build_number: ${{ needs.pre_job.outputs.build_number }}
new_version: ${{ needs.pre_job.outputs.new_version }}
with:
build_number: ${{ env.build_number }}
new_version: ${{ env.new_version }}
files: |
./*.flatpak

View file

@ -4,6 +4,16 @@ on:
push:
branches-ignore:
- 'release/[0-9]+.[0-9]+.[0-9]+'
paths-ignore:
- "**/*.md"
- README
- LICENSE
- MAINTAINERS
- CHANGELOG
- 3RD-PARTY-LICENSES
- config-samples/*
- documentation/**
- tools/**
pull_request:

View file

@ -1,6 +1,18 @@
name: macOS
on: [push, pull_request]
on:
push:
paths-ignore:
- "**/*.md"
- README
- LICENSE
- MAINTAINERS
- CHANGELOG
- 3RD-PARTY-LICENSES
- config-samples/*
- documentation/**
- tools/**
pull_request:
jobs:
pre_job:

View file

@ -31,15 +31,12 @@ jobs:
persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal token
fetch-depth: 0 # Required due to the way Git works, without it this action won't be able to find any or the correct tags
- name: Install GitVersion
uses: gittools/actions/gitversion/setup@v0.9.7
uses: gittools/actions/gitversion/setup@v4.1.0
with:
versionSpec: '5.x'
versionSpec: '6.x'
- name: Determine Version
id: gitversion
uses: gittools/actions/gitversion/execute@v0.9.7
- name: Get branch name
id: branchname
uses: nelonoel/branch-name@v1.0.1
uses: gittools/actions/gitversion/execute@v4.1.0
- name: Display GitVersion outputs
run: |
echo "Major: ${{ steps.gitversion.outputs.major }}"
@ -51,12 +48,9 @@ jobs:
echo "PreReleaseNumber: ${{ steps.gitversion.outputs.preReleaseNumber }}"
echo "WeightedPreReleaseNumber: ${{ steps.gitversion.outputs.weightedPreReleaseNumber }}"
echo "BuildMetaData: ${{ steps.gitversion.outputs.buildMetaData }}"
echo "BuildMetaDataPadded: ${{ steps.gitversion.outputs.buildMetaDataPadded }}"
echo "FullBuildMetaData: ${{ steps.gitversion.outputs.fullBuildMetaData }}"
echo "MajorMinorPatch: ${{ steps.gitversion.outputs.majorMinorPatch }}"
echo "SemVer: ${{ steps.gitversion.outputs.semVer }}"
echo "LegacySemVer: ${{ steps.gitversion.outputs.legacySemVer }}"
echo "LegacySemVerPadded: ${{ steps.gitversion.outputs.legacySemVerPadded }}"
echo "AssemblySemVer: ${{ steps.gitversion.outputs.assemblySemVer }}"
echo "AssemblySemFileVer: ${{ steps.gitversion.outputs.assemblySemFileVer }}"
echo "FullSemVer: ${{ steps.gitversion.outputs.fullSemVer }}"
@ -65,13 +59,8 @@ jobs:
echo "EscapedBranchName: ${{ steps.gitversion.outputs.escapedBranchName }}"
echo "Sha: ${{ steps.gitversion.outputs.sha }}"
echo "ShortSha: ${{ steps.gitversion.outputs.shortSha }}"
echo "NuGetVersionV2: ${{ steps.gitversion.outputs.nuGetVersionV2 }}"
echo "NuGetVersion: ${{ steps.gitversion.outputs.nuGetVersion }}"
echo "NuGetPreReleaseTagV2: ${{ steps.gitversion.outputs.nuGetPreReleaseTagV2 }}"
echo "NuGetPreReleaseTag: ${{ steps.gitversion.outputs.nuGetPreReleaseTag }}"
echo "VersionSourceSha: ${{ steps.gitversion.outputs.versionSourceSha }}"
echo "CommitsSinceVersionSource: ${{ steps.gitversion.outputs.commitsSinceVersionSource }}"
echo "CommitsSinceVersionSourcePadded: ${{ steps.gitversion.outputs.commitsSinceVersionSourcePadded }}"
echo "UncommittedChanges: ${{ steps.gitversion.outputs.uncommittedChanges }}"
echo "CommitDate: ${{ steps.gitversion.outputs.commitDate }}"
upversion-and-pr:

View file

@ -9,6 +9,9 @@ on:
- "[0-9]+.[0-9]+.[0-9]+"
types: [published]
permissions:
contents: write
jobs:
pre_job:
name: Build Preparation
@ -22,16 +25,16 @@ jobs:
fetch-depth: 0 # Required due to the way Git works, without it this action won't be able to find any or the correct tags
- name: Get release
id: get_release
uses: bruceadams/get-release@v1.2.3
uses: bruceadams/get-release@v1.3.2
env:
GITHUB_TOKEN: ${{ github.token }}
- name: Install GitVersion
uses: gittools/actions/gitversion/setup@v0.9.7
uses: gittools/actions/gitversion/setup@v4.1.0
with:
versionSpec: '5.x'
versionSpec: '6.x'
- name: Determine Version
id: gitversion
uses: gittools/actions/gitversion/execute@v0.9.7
uses: gittools/actions/gitversion/execute@v4.1.0
- name: Display GitVersion outputs
run: |
echo "Major: ${{ steps.gitversion.outputs.major }}"
@ -43,12 +46,9 @@ jobs:
echo "PreReleaseNumber: ${{ steps.gitversion.outputs.preReleaseNumber }}"
echo "WeightedPreReleaseNumber: ${{ steps.gitversion.outputs.weightedPreReleaseNumber }}"
echo "BuildMetaData: ${{ steps.gitversion.outputs.buildMetaData }}"
echo "BuildMetaDataPadded: ${{ steps.gitversion.outputs.buildMetaDataPadded }}"
echo "FullBuildMetaData: ${{ steps.gitversion.outputs.fullBuildMetaData }}"
echo "MajorMinorPatch: ${{ steps.gitversion.outputs.majorMinorPatch }}"
echo "SemVer: ${{ steps.gitversion.outputs.semVer }}"
echo "LegacySemVer: ${{ steps.gitversion.outputs.legacySemVer }}"
echo "LegacySemVerPadded: ${{ steps.gitversion.outputs.legacySemVerPadded }}"
echo "AssemblySemVer: ${{ steps.gitversion.outputs.assemblySemVer }}"
echo "AssemblySemFileVer: ${{ steps.gitversion.outputs.assemblySemFileVer }}"
echo "FullSemVer: ${{ steps.gitversion.outputs.fullSemVer }}"
@ -57,13 +57,8 @@ jobs:
echo "EscapedBranchName: ${{ steps.gitversion.outputs.escapedBranchName }}"
echo "Sha: ${{ steps.gitversion.outputs.sha }}"
echo "ShortSha: ${{ steps.gitversion.outputs.shortSha }}"
echo "NuGetVersionV2: ${{ steps.gitversion.outputs.nuGetVersionV2 }}"
echo "NuGetVersion: ${{ steps.gitversion.outputs.nuGetVersion }}"
echo "NuGetPreReleaseTagV2: ${{ steps.gitversion.outputs.nuGetPreReleaseTagV2 }}"
echo "NuGetPreReleaseTag: ${{ steps.gitversion.outputs.nuGetPreReleaseTag }}"
echo "VersionSourceSha: ${{ steps.gitversion.outputs.versionSourceSha }}"
echo "CommitsSinceVersionSource: ${{ steps.gitversion.outputs.commitsSinceVersionSource }}"
echo "CommitsSinceVersionSourcePadded: ${{ steps.gitversion.outputs.commitsSinceVersionSourcePadded }}"
echo "UncommittedChanges: ${{ steps.gitversion.outputs.uncommittedChanges }}"
echo "CommitDate: ${{ steps.gitversion.outputs.commitDate }}"
build-windows:
@ -108,24 +103,12 @@ jobs:
with:
name: Odamex-Win-x64-pdb
path: Output/pdb/*.zip
- name: Upload release binary (x64)
uses: actions/upload-release-asset@v1.0.2
env:
GITHUB_TOKEN: ${{ github.token }}
- name: Upload release binary and debug pdb (x64)
uses: softprops/action-gh-release@v2.3.4
with:
upload_url: ${{ env.upload_url }}
asset_path: ./Output/zip/odamex-win64-${{env.new_version}}.zip
asset_name: odamex-win64-${{env.new_version}}.zip
asset_content_type: application/zip
- name: Upload debug pdb (x64)
uses: actions/upload-release-asset@v1.0.2
env:
GITHUB_TOKEN: ${{ github.token }}
with:
upload_url: ${{ env.upload_url }}
asset_path: ./Output/pdb/odamex-debug-pdb-${{env.new_version}}-x64.zip
asset_name: odamex-debug-pdb-${{env.new_version}}-x64.zip
asset_content_type: application/zip
files: |
./Output/zip/odamex-win64-${{env.new_version}}.zip
./Output/pdb/odamex-debug-pdb-${{env.new_version}}-x64.zip
build-windows-x32:
name: Windows Build (Visual Studio, 32-bit)
needs: pre_job
@ -168,24 +151,12 @@ jobs:
with:
name: Odamex-Win-x86-pdb
path: Output/pdb/*.zip
- name: Upload release binary (x86)
uses: actions/upload-release-asset@v1.0.2
env:
GITHUB_TOKEN: ${{ github.token }}
- name: Upload release binary and debug pdb (x86)
uses: softprops/action-gh-release@v2.3.4
with:
upload_url: ${{ env.upload_url }}
asset_path: ./Output/zip/odamex-win32-${{env.new_version}}.zip
asset_name: odamex-win32-${{env.new_version}}.zip
asset_content_type: application/zip
- name: Upload debug pdb (x86)
uses: actions/upload-release-asset@v1.0.2
env:
GITHUB_TOKEN: ${{ github.token }}
with:
upload_url: ${{ env.upload_url }}
asset_path: ./Output/pdb/odamex-debug-pdb-${{env.new_version}}-x86.zip
asset_name: odamex-debug-pdb-${{env.new_version}}-x86.zip
asset_content_type: application/zip
files: |
./Output/zip/odamex-win32-${{env.new_version}}.zip
./Output/pdb/odamex-debug-pdb-${{env.new_version}}-x86.zip
build-flatpak:
name: Build Flatpak (Ubuntu Latest)
needs: pre_job
@ -222,22 +193,17 @@ jobs:
--default-branch=${{ env.MODIFIED_BRANCH_NAME }} -v
- name: Pack flatpak
run: |
flatpak build-bundle repo odamex.flatpak net.odamex.Odamex ${{ env.MODIFIED_BRANCH_NAME }} \
flatpak build-bundle repo odamex-linux-x86_64-${{ env.new_version }}.flatpak net.odamex.Odamex ${{ env.MODIFIED_BRANCH_NAME }} \
--runtime-repo=https://flathub.org/repo/flathub.flatpakrepo
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: Odamex-Flatpak-x86_64
path: odamex.flatpak
path: odamex-linux-x86_64-${{ env.new_version }}.flatpak
- name: Upload release binary (x86_64)
uses: actions/upload-release-asset@v1.0.2
env:
GITHUB_TOKEN: ${{ github.token }}
uses: softprops/action-gh-release@v2.3.4
with:
upload_url: ${{ env.upload_url }}
asset_path: odamex.flatpak
asset_name: odamex-linux-x86_64-${{ env.new_version }}.flatpak
asset_content_type: application/octet-stream
files: odamex-linux-x86_64-${{ env.new_version }}.flatpak
build-flatpak-arm:
name: Build Flatpak (Ubuntu 24.04 ARM)
needs: pre_job
@ -274,22 +240,19 @@ jobs:
--default-branch=${{ env.MODIFIED_BRANCH_NAME }} -v
- name: Pack flatpak
run: |
flatpak build-bundle repo odamex.flatpak net.odamex.Odamex ${{ env.MODIFIED_BRANCH_NAME }} \
flatpak build-bundle repo odamex-linux-arm64-${{ env.new_version }}.flatpak net.odamex.Odamex ${{ env.MODIFIED_BRANCH_NAME }} \
--runtime-repo=https://flathub.org/repo/flathub.flatpakrepo
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: Odamex-Flatpak-ARM64
path: odamex.flatpak
path: odamex-linux-arm64-${{ env.new_version }}.flatpak
- name: Upload release binary (ARM64)
uses: actions/upload-release-asset@v1.0.2
uses: softprops/action-gh-release@v2.3.4
env:
GITHUB_TOKEN: ${{ github.token }}
with:
upload_url: ${{ env.upload_url }}
asset_path: odamex.flatpak
asset_name: odamex-linux-arm64-${{ env.new_version }}.flatpak
asset_content_type: application/octet-stream
files: odamex-linux-arm64-${{ env.new_version }}.flatpak
package-and-upload-windows:
name: Package and Upload Artifacts
runs-on: windows-latest
@ -323,7 +286,10 @@ jobs:
run: ls
- name: Install setup compiler
shell: pwsh
run: choco install innosetup -y --no-progress
run: |
if (-not (Get-Command iscc -ErrorAction SilentlyContinue)) {
choco install innosetup -y --no-progress
}
- name: Stage and run setup compiler
shell: pwsh
run: |
@ -338,24 +304,12 @@ jobs:
with:
name: Odamex-src-zip
path: './odamex-src-${{ env.new_version }}.zip'
- name: Upload zip to Github Release Artifacts
uses: actions/upload-release-asset@v1.0.2
env:
GITHUB_TOKEN: ${{ github.token }}
- name: Upload zip and installer to Github Release Artifacts
uses: softprops/action-gh-release@v2.3.4
with:
upload_url: ${{ env.upload_url }}
asset_path: ./odamex-src-${{env.new_version}}.zip
asset_name: odamex-src-${{env.new_version}}.zip
asset_content_type: application/zip
- name: Upload installer
uses: actions/upload-release-asset@v1.0.2
env:
GITHUB_TOKEN: ${{ github.token }}
with:
upload_url: ${{ env.upload_url }}
asset_path: ./Output/odamex-win-${{env.new_version}}.exe
asset_name: odamex-win-${{env.new_version}}.exe
asset_content_type: application/octet-stream
files: |
./odamex-src-${{env.new_version}}.zip
./Output/odamex-win-${{env.new_version}}.exe
package-and-upload-unix:
name: Package and Upload Artifacts
runs-on: ubuntu-latest
@ -391,24 +345,12 @@ jobs:
with:
name: Odamex-tar-gz
path: './*.tar.gz'
- name: Upload tar.gz to Github Release Artifacts
uses: actions/upload-release-asset@v1.0.2
env:
GITHUB_TOKEN: ${{ github.token }}
- name: Upload tar.gz and tar.xz to Github Release Artifacts
uses: softprops/action-gh-release@v2.3.4
with:
upload_url: ${{ env.upload_url }}
asset_path: ./odamex-src-${{env.new_version}}.tar.gz
asset_name: odamex-src-${{env.new_version}}.tar.gz
asset_content_type: application/x-gzip
- name: Upload tar.xz to Github Release Artifacts
uses: actions/upload-release-asset@v1.0.2
env:
GITHUB_TOKEN: ${{ github.token }}
with:
upload_url: ${{ env.upload_url }}
asset_path: ./odamex-src-${{env.new_version}}.tar.xz
asset_name: odamex-src-${{env.new_version}}.tar.xz
asset_content_type: application/x-xz
files: |
./odamex-src-${{env.new_version}}.tar.gz
./odamex-src-${{env.new_version}}.tar.xz
update-winget:
name: Update WinGet package
needs: package-and-upload-windows

View file

@ -5,6 +5,9 @@ on:
branches:
- 'release/[0-9]+.[0-9]+.[0-9]+' # Only run on major.minor.patch releases
permissions:
contents: write
jobs:
pre_job:
name: Build Preparation
@ -21,12 +24,12 @@ jobs:
persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal token
fetch-depth: 0 # Required due to the way Git works, without it this action won't be able to find any or the correct tags
- name: Install GitVersion
uses: gittools/actions/gitversion/setup@v0.9.7
uses: gittools/actions/gitversion/setup@v4.1.0
with:
versionSpec: '5.x'
versionSpec: '6.x'
- name: Determine Version
id: gitversion
uses: gittools/actions/gitversion/execute@v0.9.7
uses: gittools/actions/gitversion/execute@v4.1.0
- name: Get Commits From Source
id: revlist
shell: pwsh
@ -44,12 +47,9 @@ jobs:
echo "PreReleaseNumber: ${{ steps.gitversion.outputs.preReleaseNumber }}"
echo "WeightedPreReleaseNumber: ${{ steps.gitversion.outputs.weightedPreReleaseNumber }}"
echo "BuildMetaData: ${{ steps.gitversion.outputs.buildMetaData }}"
echo "BuildMetaDataPadded: ${{ steps.gitversion.outputs.buildMetaDataPadded }}"
echo "FullBuildMetaData: ${{ steps.gitversion.outputs.fullBuildMetaData }}"
echo "MajorMinorPatch: ${{ steps.gitversion.outputs.majorMinorPatch }}"
echo "SemVer: ${{ steps.gitversion.outputs.semVer }}"
echo "LegacySemVer: ${{ steps.gitversion.outputs.legacySemVer }}"
echo "LegacySemVerPadded: ${{ steps.gitversion.outputs.legacySemVerPadded }}"
echo "AssemblySemVer: ${{ steps.gitversion.outputs.assemblySemVer }}"
echo "AssemblySemFileVer: ${{ steps.gitversion.outputs.assemblySemFileVer }}"
echo "FullSemVer: ${{ steps.gitversion.outputs.fullSemVer }}"
@ -58,13 +58,8 @@ jobs:
echo "EscapedBranchName: ${{ steps.gitversion.outputs.escapedBranchName }}"
echo "Sha: ${{ steps.gitversion.outputs.sha }}"
echo "ShortSha: ${{ steps.gitversion.outputs.shortSha }}"
echo "NuGetVersionV2: ${{ steps.gitversion.outputs.nuGetVersionV2 }}"
echo "NuGetVersion: ${{ steps.gitversion.outputs.nuGetVersion }}"
echo "NuGetPreReleaseTagV2: ${{ steps.gitversion.outputs.nuGetPreReleaseTagV2 }}"
echo "NuGetPreReleaseTag: ${{ steps.gitversion.outputs.nuGetPreReleaseTag }}"
echo "VersionSourceSha: ${{ steps.gitversion.outputs.versionSourceSha }}"
echo "CommitsSinceVersionSource: ${{ steps.gitversion.outputs.commitsSinceVersionSource }}"
echo "CommitsSinceVersionSourcePadded: ${{ steps.gitversion.outputs.commitsSinceVersionSourcePadded }}"
echo "UncommittedChanges: ${{ steps.gitversion.outputs.uncommittedChanges }}"
echo "CommitDate: ${{ steps.gitversion.outputs.commitDate }}"
echo "TotalCommits: ${{ steps.revlist.outputs.totalCommits }}"
@ -175,6 +170,8 @@ jobs:
new_version: ${{ needs.pre_job.outputs.new_version }}
steps:
- uses: actions/checkout@v4
with:
fetch-tags: true
- name: Run Upversion
id: upversion
shell: pwsh
@ -196,7 +193,10 @@ jobs:
name: Odamex-Win-x64
- name: Install setup compiler
shell: pwsh
run: choco install innosetup -y --no-progress
run: |
if (-not (Get-Command iscc -ErrorAction SilentlyContinue)) {
choco install innosetup -y --no-progress
}
- name: Stage and run setup compiler
shell: pwsh
run: |
@ -206,3 +206,23 @@ jobs:
with:
name: Odamex-Installer
path: 'Output/*.exe'
- name: Download x86 pdb
uses: actions/download-artifact@v4
with:
name: Odamex-Win-x86-pdb
- name: Download x64 pdb
uses: actions/download-artifact@v4
with:
name: Odamex-Win-x64-pdb
- name: Create or update prerelease
uses: ./.github/actions/update-prerelease
env:
build_number: ${{ needs.pre_job.outputs.build_number }}
new_version: ${{ needs.pre_job.outputs.new_version }}
with:
build_number: ${{ env.build_number }}
new_version: ${{ env.new_version }}
files: |
./odamex-win*.zip
./odamex-debug-*.zip
./Output/*.exe

View file

@ -4,6 +4,16 @@ on:
push:
branches-ignore:
- 'release/[0-9]+.[0-9]+.[0-9]+'
paths-ignore:
- "**/*.md"
- README
- LICENSE
- MAINTAINERS
- CHANGELOG
- 3RD-PARTY-LICENSES
- config-samples/*
- documentation/**
- tools/**
pull_request:

4
.gitignore vendored
View file

@ -1,6 +1,8 @@
.DS_Store
/build*
/.cache
*.vscode
*.zed
# Used by Visual Studio when loading this project as a folder, which uses CMake.
/.vs
@ -16,4 +18,4 @@ CMakeSettings.json
/packaging/flatpak/.flatpak-builder
# Generated by fmtlib when building with VS
/libraries/fmt/run-msbuild.bat
/libraries/fmt/run-msbuild.bat

1
.gitmodules vendored
View file

@ -21,7 +21,6 @@
[submodule "libraries/jsoncpp"]
path = libraries/jsoncpp
url = https://github.com/open-source-parsers/jsoncpp.git
branch = 0.y.z
ignore = dirty
[submodule "libraries/portmidi"]
path = libraries/portmidi

1
.mailmap Normal file
View file

@ -0,0 +1 @@
Lexi Mayfield <me@leximayfield.com> <alexmax2742@gmail.com>

View file

@ -14,7 +14,7 @@
cmake_minimum_required(VERSION 3.13)
project(Odamex VERSION 11.1.1)
project(Odamex VERSION 12.0.0)
include(CMakeDependentOption)
@ -78,14 +78,12 @@ if(NOT APPLE AND NOT WIN32)
endif()
set(PROJECT_COPYRIGHT "2006-2025")
set(PROJECT_RC_VERSION "11,1,1,0")
set(PROJECT_RC_VERSION "12,0,0,0")
set(PROJECT_COMPANY "The Odamex Team")
# Include early required commands for specific systems
if (NSWITCH)
include("switch.cmake" REQUIRED) # Nintendo Switch
elseif(VWII)
include("wii.cmake" REQUIRED) # Wii/vWii
endif()
# Ensure that we can use folders in projects.

5
GitVersion.yml Normal file
View file

@ -0,0 +1,5 @@
branches:
release:
regex: ^release[/-]
prevent-increment:
when-current-commit-tagged: true

View file

@ -1,17 +1,19 @@
This code is maintained on https://github.com/odamex/odamex
Post bugs to https://github.com/odamex/odamex/issues
IRC: irc.oftc.net #odamex
DISCORD: https://discord.gg/bvvMJMS
Find the Odamex code at: https://github.com/odamex/odamex
Post bugs to: https://github.com/odamex/odamex/issues
Read our documentation at: https://github.com/odamex/odamex/wiki
Visit our Discord server: https://discord.gg/bvvMJMS
Sean: sean@odamex.net (lead coder) <- patches
Manc: mike@odamex.net (services and odamex.net website admin, project manager) <- patches
Ralphis: ralphis@odamex.net (project manager)
Russell: russell@odamex.net (launcher coder, coder) <- patches
Hyper_Eye: mwoodj@huntsvegas.org (coder, osx and xbox package manager)
deathz0r: deathz0r@odamex.net (documentation, testing and code cleanups)
Ch0wW: ch0ww@baseq.fr (documentation, testing and code cleanups)
electricbrass: electricbrass@proton.me (Programmer, Linux Flatpak Maintainer)
Hekksy: (Project Manager)
Hyper_Eye: mwoodj@huntsvegas.org (Programmer, macOS Package Manager)
KBlair: (Programmer)
LexiMax: (Programmer)
Manc: mike@odamex.net (odamex.net Services & Website Administrator, Project Manager)
Ralphis: ralphis@gmail.com (Project Manager)
Sean: sean@odamex.net (Programmer)
Portions of the save/load game system code not already present provided by Marisa from
zdoom 1.22 relicensed under the GNU/GPL v2.
Portions of the save/load game system code not
already present provided by Marisa from zdoom 1.22
relicensed under the GNU/GPL v2.
An archive of our old bug tracker system is available at http://odamex.net/bugs
Updated October 14, 2025

2
README
View file

@ -1,5 +1,5 @@
===============================================================================
Odamex v11.1.1 README
Odamex v12.0.0 README
https://odamex.net
===============================================================================

View file

@ -2,7 +2,7 @@
| Windows Build Status | Mac Build Status | Linux Build Status | Join our Discord! |
| -------------------- | ---------------- | ------------------ | ----------------- |
| [![Windows](https://github.com/odamex/odamex/workflows/Windows/badge.svg)](https://github.com/odamex/odamex/actions?query=workflow%3AWindows) | [![macOS](https://github.com/odamex/odamex/workflows/macOS/badge.svg)](https://github.com/odamex/odamex/actions?query=workflow%3AmacOS) | [![Linux](https://github.com/odamex/odamex/workflows/Linux/badge.svg)](https://github.com/odamex/odamex/actions?query=workflow%3ALinux) | [![Join our discord](https://discordapp.com/api/guilds/236518337671200768/widget.png?style=shield)](https://discord.gg/aMUzcZE) |
| [![Windows](https://github.com/odamex/odamex/actions/workflows/windows.yml/badge.svg)](https://github.com/odamex/odamex/actions/workflows/windows.yml) | [![macOS](https://github.com/odamex/odamex/actions/workflows/macos.yml/badge.svg)](https://github.com/odamex/odamex/actions/workflows/macos.yml) | [![Linux](https://github.com/odamex/odamex/actions/workflows/linux.yml/badge.svg)](https://github.com/odamex/odamex/actions/workflows/linux.yml) | [![Join our discord](https://discordapp.com/api/guilds/236518337671200768/widget.png?style=shield)](https://discord.gg/aMUzcZE) |
Odamex is a modification of DOOM to allow players to compete with each other over the Internet using a client/server architecture. Thanks to the source code release of DOOM by id Software in December 1997, there have been many modifications that enhanced DOOM in various ways. These modifications are known as "source ports", as early modifications mainly ported DOOM to other platforms and operating systems such as Windows and Macintosh.
@ -16,7 +16,7 @@ Odamex supports the following features:
* Full Client/Server multiplayer architecture with network compensation features (unlagged, client interpolation and prediction)
* Support for up to 255 players
* Various compatibility settings, to emulate vanilla Doom, Boom, or ZDoom physics and fixes
* Playback and recording of vanilla demos
* Playback of vanilla demos
* A fully-featured client netdemo record system with playback control
* Removal of most vanilla Doom Static limits
* Support for most Boom and MBF mapping features

View file

@ -1,313 +0,0 @@
===============================================================================
Odamex v11.1.1 for Xbox
http://odamex.net/
Authored by:
Michael "Hyper_Eye" Wood
Revision date: November 8, 2020
===============================================================================
Table of contents:
1. Introduction
1.1 What is Odamex?
1.2 Xbox Features at a Glance
2. Installation
2.1 Requirements
2.2 Installation - binary download
2.3 Installation - source download
3. Xbox Controls
3.1 Launcher
3.2 Game Client
4. Issues
4.1 TODO
4.2 Known Issues
4.3 Bug Reporting
5. Frequently Asked Questions
6. Acknowledgements
===============================================================================
Section 1: Introduction
1.1 What is Odamex?
Odamex is a modification of DOOM to allow players to compete with each other
over the Internet using the client/server architecture. Odamex also provides
a feature-rich single-player engine.
Please see the general README provided with Odamex for a thorough description
of Odamex and its features.
1.2 Xbox Features at a Glance
* Supports all online game modes and features that are available on other
platforms
* Game launcher with server browser and solo launcher with wad selector
* Multiple wad search paths can be configured
* Complete analog Xbox controller support with configurable axis assignments,
turn sensitivity, optional freelook, and configurable button bindings
* Support for USB mouse and keyboard
* Saved games and configuration files are stored in UDATA and TDATA paths so
they integrate properly with the official memory manager as well as
homebrew dashboards complete with icons
* Saved games can be deleted using the memory manager
* Saved games can be copied to and from a memory card
* Vanilla 320x200 resolution, multiple SDTV resolutions including 480i, and
HDTV resolutions up to 720p are supported
===============================================================================
Section 2. Installation
2.1 - Requirements
Odamex requires a modded Xbox in order to operate.
2.2 - Installation - binary download
Binary downloads of Odamex are not available from odamex.net or any site
associated with The Odamex Team. Because Odamex is built with the official
XDK binary builds cannot be provided.
2.3 - Installation - source download
If you are interested in the bleeding edge development of Odamex, you can
access the SVN at http://odamex.net/svn/root with anonymous read access. Be
warned however that it might be incompatible with current release versions,
and stability is not guaranteed.
The following libraries are required:
* SDLx (http://svn.huntsvegas.org/wsvn/SDLx)
Additionally the launcher also requires SDLx and the following libraries:
* pthreads-Xbox (http://svn.huntsvegas.org/wsvn/pthreads-xbox)
* Agar (http://www.libagar.org)
Building the Odamex and AG-Odalaunch source for Xbox requries the use of the
Microsoft Xbox Software Development kit (a.k.a XDK). You must be a Microsoft
approved Xbox developer to gain access to the required software.
===============================================================================
Section 3: Xbox Controls
3.1 - Launcher
Left Analog Stick - Move Cursor
Left/Right Trigger - Increment/Decrement list selection by 10
D-Pad Up/Down - Increment/Decrement list selection by 1
Left/Right Trigger (Held) - Scroll list selection
D-Pad up/Down (Held) - Scroll list selection
D-Pad Left/Right - Cycle focused widget/button
A Button - Activate cursor selection
B Button - Activate focused widget/button
3.2 - Game Client
The D-Pad is used to navigate the game menus while A activates
items within the menu and B returns to the previous menu.
When the console is down the left and right triggers scroll.
Default Controller Binding:
Left Analog Stick X Axis - Step left/right
Left Analog Stick Y Axis - Move forward/backward
Right Analog Stick X Axis - Turn Left/Right
Right Analog Stick Y Axis - Look Up/Down (Freelook disabled by default)
Right Analog Stick Push Down - Center View
D-Pad Up - Say
D-Pad Right - Team Say
D-Pad Down - Quick Swap to Shotgun & Toggle SG/SSG
D-Pad Left - Spectate/Spy Next
Left Trigger - Walk/Run
Right Trigger - Attack/Fire Weapon
A Button - Activate
X Button - Strafe
B Button - Next Weapon
Y Button - Previous Weapon
White Button - Scoreboard
Black Button - Toggle Automap
Start Button - Menu (Not Configurable)
Back Button - Toggle Console
===============================================================================
Section 4: Issues
4.1 - TODO
* Virtual (On-Screen) Keyboard
* Configurable overscan in launcher
* Rumble
* Use a DVD as a wad source
* Further optimization (Improve 720p performance)
4.2 - Known Issues
* The game currently cannot be launched from a DVD. This is hampered by a bug
that is very difficult to debug.
* Controller events are not received in the launcher while the master list is
being queried or a complete server list refresh is taking place. Joystick
events are disabled during these tasks because of a mutex issue or race
condition that results in a freeze before processing the final queried
server. The cursor can be moved with a mouse during these tasks.
* The "Query Master On Start" launcher option does not work. It might be that
the Xbox network controller takes a little longer to initialize but I
don't really know at this point.
* You must hit A inside the main launcher window before you can use B to
activate a focused widget. This is due to a window focus issue.
* The version of SDLx used with Odamex supports 1080i but 1080i has been
disabled in the library as it is not currently usable in Odamex. Selecting
1080i results in unplayable framerate and likely a crash when the system
runs out of memory.
* SDLx reports all 4 joystick ports as active regardless of whether or not a
joystick is plugged in. If the active joystick selection is changed to a
port that does not have a joystick plugged in control may be lost and a
reboot is required or the selection must be changed with a keyboard.
4.3 - Bug Reporting
Please report any bugs you find at http://www.odamex.net/bugs
Your bug submissions help us make Odamex better. Thank you!
===============================================================================
Section 5: Frequently Asked Questions
Q. How do I communicate with other players?
A. Currently there is no way to insert text using the Xbox controller. Xbox
players can communicate by either plugging in a USB keyboard or by using
chat macros. A virtual keyboard is a planned feature.
Q. How do the chat macros work?
A. While in a multiplayer game push either "Say" (default: D-Pad Up) or
"Team Say" (default: D-Pad Right). You can then insert a macro by
pushing D-Pad Up + the macro button that corresponds to the message
you wish to insert. For example, to say "Hi" to everyone in the game
you would press D-Pad Up and then D-Pad Up + A.
The default macros on Xbox are as follows:
A - "Hi."
B - "I'm ready to kick butt!"
X - "Help!"
Y - "GG"
White - "Yes"
Black - "No"
Left Trigger - "I'll take care of it."
Right Trigger - "Come here!"
Start - "Thanks for the game. Bye."
Back - "I am on Xbox and can only use chat macros."
Q. How can I customize the chat macros?
A. You will need to manually change them in your odamex.cfg file.
To do this perform the following steps:
1) Launch the Odamex game client from the launcher (a solo game is fine)
2) Quit Odamex using the game menus (turning off the power without
quitting will discard configuration changes.)
3) Quit the launcher and return to your dashboard.
4) FTP into the machine or use another method of accessing the file system.
5) Copy E:\TDATA\4f444d58\odamex.cfg to your computer.
6) Open odamex.cfg in an editor.
7) Find the "chatmacro" options and change them as desired (note the order
as they correspond to controller buttons above.)
8) Save the file.
9) Copy odamex.cfg back to E:\TDATA\4f444d58\odamex.cfg
Q. How do I change my player name without a keyboard?
A. You will need to manually change the setting for your player name in
your odamex.cfg file. To do this perform the following steps:
1) Launch the Odamex game client from the launcher (a solo game is fine)
2) Quit Odamex using the game menus (turning off the power without
quitting will discard configuration changes.)
3) Quit the launcher and return to your dashboard.
4) FTP into the machine or use another method of accessing the file system.
5) Copy E:\TDATA\4f444d58\odamex.cfg to your computer.
6) Open odamex.cfg in an editor.
7) Find the "cl_name" option and change the name to your desired handle.
8) Save the file.
9) Copy odamex.cfg back to E:\TDATA\4f444d58\odamex.cfg
Q. What is required to use a keyboard and/or mouse?
A. A simple USB-to-Xbox adapter will work. These can be easily obtained
from online stores and auction sites for little cost. A device with a
cable modified to use an Xbox safety release cable will also work.
Q. Is it safe to try all the resolutions listed in the resolution list?
A. SDLx scales all resolutions to 640x480 except for 720x480 and 1280x720.
Only resolutions that are supported by the AV pack and system settings
are shown.
Q. I have a widescreen television but the 720x480 options isn't available?
A. In your Xbox system video settings select "Wide Screen" or "Letterbox".
Q. I have an HDTV and the HDTV AV Pack but the 1280x720 (720p) option isn't
available?
A. In your Xbox system video settings enable the 720p HDTV resolution.
===============================================================================
Section 6: Acknowledgements
This port would not be possible without the contributions and assistance of
many people. The following especially deserve to be mentioned.
* Undead of Team Assembly - Undead donated 2 Xbox debug kits that proved
to be instrumental in the development of the libraries that Odamex
depends on as well as Odamex itself. HUGE thanks to him for his
kind donation!
* Vedge of Hypertriton, Inc. (Developer of Agar) - Agar is a critical
piece that serves as the cross-platform GUI toolkit behind AG-Odalaunch.
Vedge provided assistance and knowledge as well as bug fixes and feature
enhancements that directly benefited the Xbox and the development of
AG-Odalaunch. He also trusted me with commit access so that I could
more efficiently get code changes into Agar. Thanks for not getting
annoyed while I flooded the channel with my thoughts, inquiries, and
general ramblings.
* Sirlemonhead - Sirlemonhead helped get me set up for development and I
e-mailed him with questions and ideas on many occasions. Also, he made
the AvP port and nobody can thank him enough for that.
* weinerschnitzel - Provided testing and feedback throughout development.
* ldotsfan - Bouncing Xbox development tricks back and forth with him has
been both an enjoyable and educational experience and I look forward
to more of the same.
* Likklebaer - Thanks for your role in Doom-X and for sharing your experience.
* To all those at Xbox-Scene that have provided interest, suggestions, and
great encouragement. I hope you guys love playing this port as much as I
enjoy working on it - Clockface, Cheema201, guybird, ultimate509, neil222,
moonmaster1, lawdawg0931, Mega Man (?), flux2k, Pulsemasta, rubarb, Koooi,
Finker282, Rygrass, trrobin, |11|1VeNoM1|11|, XTecuterX73
* Special thanks to the faithful Odamex bug testers and patch contributers who
put up with our crap on a daily basis because they believe in Odamex and
the philosophies behind it - Spleen, Ladna, HeX9101, tm512, GhostlyDeath,
and a hat tip to blzut3
* To anyone I missed and all the developers in the Xbox development scene that
released source and made it possible to work on the system without being
completely lost. The Xbox Linux guys, XBMC devs, Arnova and the rest of the
XBMC4Xbox devs, XPort, madmab, Team Assembly, RessurectionXtras, Team Evox,
MXM devs, everyone who has contributed to openxdk, and all the rest.
* Finally, all the members of the Odamex development team. Working with you
guys is great. I appreciate the maturity, intelligence, and dedication each
of you has brought to the team. It is the level-headedness and respect that
everyone working on this project maintains that will see Odamex succeed as
a great open-source project and Doom source port - Manc, Russell, Ralphis,
Denis, and NES
===============================================================================

View file

@ -1,624 +0,0 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id$
//
// Copyright (C) 2006-2025 by The Odamex Team.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//
// DESCRIPTION:
// Xbox Support
//
//-----------------------------------------------------------------------------
#ifdef _XBOX
#include <xtl.h>
#include <iostream>
#include <string>
#include <iomanip>
#include <sstream>
#include <list>
#include <errno.h>
#include "i_xbox.h"
#include "i_system.h"
using namespace std;
// Xbox drive letters
#define DriveC "\\??\\C:"
#define DriveD "\\??\\D:"
#define DriveE "\\??\\E:"
#define DriveF "\\??\\F:"
#define DriveG "\\??\\G:"
#define DriveT "\\??\\T:"
#define DriveU "\\??\\U:"
#define DriveZ "\\??\\Z:"
// Partition device mapping
#define DeviceC "\\Device\\Harddisk0\\Partition2"
#define CdRom "\\Device\\CdRom0"
#define DeviceE "\\Device\\Harddisk0\\Partition1"
#define DeviceF "\\Device\\Harddisk0\\Partition6"
#define DeviceG "\\Device\\Harddisk0\\Partition7"
#define DeviceT "\\Device\\Harddisk0\\Partition1\\TDATA\\4F444D58"
#define DeviceU "\\Device\\Harddisk0\\Partition1\\UDATA\\4F444D58"
#define DeviceZ "\\Device\\Harddisk0\\Partition5"
// Custom LAUNCH_DATA struct for external XBE execution from AG_Execute()
#define AG_LAUNCH_MAGIC 0x41474152
typedef struct {
DWORD magic; // Test this against AG_LAUNCH_MAGIC to know this special struct was used
DWORD dwID; // The Title ID of the launcher XBE
CHAR szLauncherXBE[256]; // The full path to the launcher XBE
CHAR szLaunchedXBE[256]; // The full path to the launched XBE
CHAR szCmdLine[MAX_LAUNCH_DATA_SIZE - 520]; // The command-line parameters
} AG_LAUNCH_DATA, *PAG_LAUNCH_DATA;
// Standard homebrew custom LAUNCH_DATA designed to launch emu's directly into a game.
// This is used to pass custom parameters from many popular dashboards such as XBMC.
#define CUSTOM_LAUNCH_MAGIC 0xEE456777
typedef struct {
DWORD magic;
CHAR szFilename[300];
CHAR szLaunchXBEOnExit[100];
CHAR szRemap_D_As[350];
BYTE country;
BYTE launchInsertedMedia;
BYTE executionType;
CHAR reserved[MAX_LAUNCH_DATA_SIZE-757];
} CUSTOM_LAUNCH_DATA, *PCUSTOM_LAUNCH_DATA;
#define INVALID_FILE_ATTRIBUTES -1
typedef struct _STRING
{
USHORT Length;
USHORT MaximumLength;
PSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING, ANSI_STRING, *PANSI_STRING;
// These are undocumented Xbox functions that are not in the XDK includes.
// They can be found by looking through the symbols found in the Xbox libs (xapilib.lib mostly).
extern "C" XBOXAPI LONG WINAPI IoCreateSymbolicLink(IN PUNICODE_STRING SymbolicLinkName,IN PUNICODE_STRING DeviceName);
extern "C" XBOXAPI LONG WINAPI IoDeleteSymbolicLink(IN PUNICODE_STRING SymbolicLinkName);
extern "C" XBOXAPI INT WINAPI XWriteTitleInfoAndRebootA(LPVOID,LPVOID,DWORD,DWORD,LPVOID);
extern "C" XBOXAPI LONG WINAPI HalWriteSMBusValue(UCHAR devddress, UCHAR offset, UCHAR writedw, DWORD data);
// External function declarations
extern int I_Main(int argc, char *argv[]); // i_main.cpp
extern size_t I_BytesToMegabytes (size_t Bytes); // i_system.cpp
//Globals
static std::list<void (*)(void)> ExitFuncList;
static DWORD LauncherID;
static char *LauncherXBE = NULL;
static bool Xbox_RROD = false; // Novelty - Red Ring of DOOM!
//
// xbox_Getenv
// Environment variables don't exist on Xbox. Return NULL.
//
char *xbox_Getenv(const char *)
{
return NULL;
}
//
// xbox_Putenv
//
// Environment variables don't exist on Xbox. Just return success.
//
int xbox_Putenv(const char *)
{
return 0;
}
//
// xbox_GetCWD
//
// Return working directory which is always D:\
//
char *xbox_GetCWD(char *buf, size_t size)
{
if(size > 0 && buf)
{
if(size >= 3)
{
strcpy(buf, "D:\\");
return buf;
}
else
errno = ERANGE;
}
else
errno = EINVAL;
return NULL;
}
//
// xbox_InetNtoa
//
char *xbox_InetNtoa(struct in_addr in)
{
static char addr[32];
sprintf(addr, "%d.%d.%d.%d",
in.S_un.S_un_b.s_b1,
in.S_un.S_un_b.s_b2,
in.S_un.S_un_b.s_b3,
in.S_un.S_un_b.s_b4);
return addr;
}
//
// xbox_GetHostByName
//
// Custom implementation for Xbox
//
struct hostent *xbox_GetHostByName(const char *name)
{
static struct hostent *he = NULL;
unsigned long addr = INADDR_NONE;
WSAEVENT hEvent;
XNDNS *pDns = NULL;
INT err;
if(!name)
return NULL;
// This data is static and it should not be freed.
if(!he)
{
he = (struct hostent *)malloc(sizeof(struct hostent));
if(!he)
{
// Failed to allocate!
return NULL;
}
he->h_addr_list = (char **)malloc(sizeof(char*));
he->h_addr_list[0] = (char *)malloc(sizeof(struct in_addr));
}
if(isdigit(name[0]))
addr = inet_addr(name);
if(addr != INADDR_NONE)
*(int *)he->h_addr_list[0] = addr;
else
{
hEvent = WSACreateEvent();
err = XNetDnsLookup(name, hEvent, &pDns);
WaitForSingleObject( (HANDLE)hEvent, INFINITE);
if(!pDns || pDns->iStatus != 0)
return NULL;
memcpy(he->h_addr_list[0], pDns->aina, sizeof(struct in_addr));
XNetDnsRelease(pDns);
WSACloseEvent(hEvent);
}
return he;
}
//
// xbox_GetHostname
//
// Custom implementation for Xbox
//
int xbox_GetHostname(char *name, int namelen)
{
XNADDR xna;
DWORD dwState;
if(name)
{
if(namelen > 0)
{
dwState = XNetGetTitleXnAddr(&xna);
XNetInAddrToString(xna.ina, name, namelen);
return 0;
}
else
errno = EINVAL;
}
else
errno = EFAULT;
return -1;
}
//
// xbox_PrintMemoryDebug
//
void xbox_PrintMemoryDebug()
{
MEMORYSTATUS stat;
static DWORD lastmem = 0;
char buf[100];
// Get the memory status.
GlobalMemoryStatus(&stat);
if (stat.dwAvailPhys != lastmem)
{
sprintf(buf, "\nMemory Debug:\n");
OutputDebugString( buf );
sprintf(buf, "Total Physical Memory: \t%4d bytes / %4d MB\n", stat.dwTotalPhys, I_BytesToMegabytes(stat.dwTotalPhys));
OutputDebugString( buf );
sprintf(buf, "Used Physical Memory : \t%4d bytes / %4d MB\n", stat.dwTotalPhys - stat.dwAvailPhys,
I_BytesToMegabytes(stat.dwTotalPhys - stat.dwAvailPhys));
OutputDebugString( buf );
sprintf(buf, "Free Physical Memory : \t%4d bytes / %4d MB\n", stat.dwAvailPhys, I_BytesToMegabytes(stat.dwAvailPhys));
OutputDebugString( buf );
OutputDebugString("\n");
lastmem = stat.dwAvailPhys;
}
}
//
// xbox_MountDevice
//
// XBox device mounting
//
LONG xbox_MountDevice(LPSTR sSymbolicLinkName, LPSTR sDeviceName)
{
UNICODE_STRING deviceName;
deviceName.Buffer = sDeviceName;
deviceName.Length = (USHORT)strlen(sDeviceName);
deviceName.MaximumLength = (USHORT)strlen(sDeviceName) + 1;
UNICODE_STRING symbolicLinkName;
symbolicLinkName.Buffer = sSymbolicLinkName;
symbolicLinkName.Length = (USHORT)strlen(sSymbolicLinkName);
symbolicLinkName.MaximumLength = (USHORT)strlen(sSymbolicLinkName) + 1;
return IoCreateSymbolicLink(&symbolicLinkName, &deviceName);
}
//
// xbox_UnMountDevice
//
LONG xbox_UnMountDevice(LPSTR sSymbolicLinkName)
{
UNICODE_STRING symbolicLinkName;
symbolicLinkName.Buffer = sSymbolicLinkName;
symbolicLinkName.Length = (USHORT)strlen(sSymbolicLinkName);
symbolicLinkName.MaximumLength = (USHORT)strlen(sSymbolicLinkName) + 1;
return IoDeleteSymbolicLink(&symbolicLinkName);
}
//
// xbox_MountPartitions
//
// Some of these partitions are automatically mounted but just
// to be on the safe side the mount will be attempted anyway
//
// Some of these partitions are only found on some modded consoles.
// These partitions will only successfully mount on consoles where
// the modder has created these partitions.
//
// F is likely to be found on systems that shipped with stock hdd's
// that were 10GB in size. Since the Xbox hdd was advertised as 8GB,
// 2GB were left unpartitioned on these and that extra space will
// typically be partitioned into F: during modding and games or apps
// will be installed there (like this one.) F: will also be found
// on non-stock hdd's of any size where any space above 8GB and below
// 137GB will be partitioned into F:
//
// G is likely to be found on non-stock hdd's that are larger than 137GB
// due to the partition size limitation. Anything above 137GB is partitioned
// into G: and it is used, typically, for the same purposes as F.
//
void xbox_MountPartitions()
{
xbox_MountDevice(DriveD, CdRom); // DVD-ROM or start path - automounted
xbox_MountDevice(DriveE, DeviceE); // Standard save partition
xbox_MountDevice(DriveF, DeviceF); // Non-stock partition - modded consoles only
xbox_MountDevice(DriveG, DeviceG); // Non-stock partition - modded consoles only
xbox_MountDevice(DriveT, DeviceT); // Odamex's unique TDATA - peristent save data (configs, etc.) - automounted
xbox_MountDevice(DriveU, DeviceU); // Odamex's unique UDATA - user save data (save games) - automounted
xbox_MountDevice(DriveZ, DeviceZ); // Cache partition - appropriate place for temporary files - automounted
}
//
// xbox_UnMountPartitions
//
void xbox_UnMountPartitions()
{
xbox_UnMountDevice(DriveD);
xbox_UnMountDevice(DriveE);
xbox_UnMountDevice(DriveF);
xbox_UnMountDevice(DriveG);
xbox_UnMountDevice(DriveT);
xbox_UnMountDevice(DriveU);
xbox_UnMountDevice(DriveZ);
}
//
// xbox_InitNet
//
void xbox_InitNet()
{
XNetStartupParams xnsp;
ZeroMemory( &xnsp, sizeof(xnsp) );
xnsp.cfgSizeOfStruct = sizeof(xnsp);
xnsp.cfgPrivatePoolSizeInPages = 64; // == 256kb, default = 12 (48kb)
xnsp.cfgEnetReceiveQueueLength = 16; // == 32kb, default = 8 (16kb)
xnsp.cfgIpFragMaxSimultaneous = 16; // default = 4
xnsp.cfgIpFragMaxPacketDiv256 = 32; // == 8kb, default = 8 (2kb)
xnsp.cfgSockMaxSockets = 64; // default = 64
xnsp.cfgSockDefaultRecvBufsizeInK = 128; // default = 16
xnsp.cfgSockDefaultSendBufsizeInK = 128; // default = 16
// Bypass security so we can talk to the outside world as we please
xnsp.cfgFlags = XNET_STARTUP_BYPASS_SECURITY;
XNetStartup( &xnsp );
}
//
// xbox_CloseNetwork
//
void xbox_CloseNetwork()
{
XNetCleanup();
}
//
// xbox_WriteSaveMeta
//
void xbox_WriteSaveMeta(string path, string text)
{
if(!path.size() || !text.size())
return;
string filename = path + PATHSEP + "SaveMeta.xbx";
ofstream metafile(filename.c_str());
if(metafile.fail())
{
I_Error ("Failed to create %s save meta:\n%s",
filename.c_str(), strerror (errno));
return;
}
metafile << "Name=" << text;
metafile.close();
}
//
// xbox_GetSavePath
//
string xbox_GetSavePath(string file, int slot)
{
ostringstream path;
DWORD attrs;
path << setiosflags(ios::right);
path << setfill('0');
path << "U:" << PATHSEP << setw(12) << slot;
if((attrs = GetFileAttributes(path.str().c_str())) == INVALID_FILE_ATTRIBUTES)
{
if(!SUCCEEDED(CreateDirectory(path.str().c_str(), NULL)))
{
I_FatalError ("Failed to create %s directory:\n%s",
path.str().c_str(), strerror (errno));
}
xbox_WriteSaveMeta(path.str(), "Empty Slot");
}
else
{
if (!(attrs & FILE_ATTRIBUTE_DIRECTORY))
I_FatalError ("%s must be a directory", path.str().c_str());
}
path << PATHSEP << file;
return path.str();
}
//
// xbox_EnableCustomLED
//
void xbox_EnableCustomLED()
{
// 0xF0 = Solid Red
HalWriteSMBusValue(0x20, 0x08, 0, 0xF0);
Sleep(10);
HalWriteSMBusValue(0x20, 0x07, 0, 1);
}
//
// xbox_DisableCustomLED
//
void xbox_DisableCustomLED()
{
HalWriteSMBusValue(0x20, 0x07, 0, 0);
}
//
// xbox_RecordLauncherXBE
//
void xbox_RecordLauncherXBE(char *szLauncherXBE, DWORD dwID)
{
if(szLauncherXBE && !LauncherXBE)
{
LauncherXBE = strdup(szLauncherXBE);
LauncherID = dwID;
}
}
//
// xbox_reboot
//
// Exit Odamex and perform a warm reboot (no startup logo) to a launcher or dashboard
//
void xbox_Reboot()
{
LD_LAUNCH_DASHBOARD launchData = { XLD_LAUNCH_DASHBOARD_MAIN_MENU };
// If Odamex was started from a launcher we want to return to it.
if(LauncherXBE)
{
size_t pathLen;
char *mntDev;
char *p;
// Determine the necessary D: mapping for the launcher XBE
p = strrchr(LauncherXBE, PATHSEPCHAR);
pathLen = p - LauncherXBE;
mntDev = (char *)malloc(pathLen + 1);
memcpy(mntDev, LauncherXBE, pathLen);
mntDev[pathLen] = '\0'; // This is necessary
p++; // Now conveniently Points to the start of our XBE name with path stripped off.
// Return to the launcher XBE
XWriteTitleInfoAndRebootA(p, mntDev, LDT_TITLE, LauncherID, &launchData);
}
// Return to the dashboard
XLaunchNewImage( NULL, (LAUNCH_DATA*)&launchData );
}
//
// xbox_AtExit
//
// Custom atexit function for Xbox
//
void xbox_AtExit(void (*function)(void))
{
if(function)
ExitFuncList.push_back(function);
}
//
// xbox_Exit
//
// Custom exit function for Xbox
//
void xbox_Exit(int status)
{
std::list<void (*)(void)>::iterator funcIter;
for(funcIter = ExitFuncList.begin(); funcIter != ExitFuncList.end(); ++funcIter)
(*funcIter)();
xbox_CloseNetwork();
xbox_UnMountPartitions();
if(Xbox_RROD)
xbox_DisableCustomLED();
xbox_Reboot();
}
//
// xbox_PrepareArgs
//
// Convert to standard C arguments
void xbox_PrepareArgs(string cmdline, char *argv[], int &argc)
{
if(cmdline.size())
{
size_t pos, oldpos = 0;
do
{
if(cmdline[oldpos] == '"')
pos = cmdline.find('"', ++oldpos);
else
pos = cmdline.find(' ', oldpos);
if(pos != oldpos)
{
argv[argc] = strdup(cmdline.substr(oldpos, pos - oldpos).c_str());
if(!stricmp(argv[argc], "-rrod"))
Xbox_RROD = true;
argc++;
}
oldpos = pos + 1;
} while(pos != string::npos);
}
argv[argc] = NULL;
}
//
// main
//
// Entry point on Xbox
//
void __cdecl main()
{
DWORD launchDataType;
LAUNCH_DATA launchData;
char *xargv[100];
int xargc = 1;
xargv[0] = strdup("D:\\default.xbe"); // mimic argv[0]
if(XGetLaunchInfo (&launchDataType, &launchData) == ERROR_SUCCESS)
{
// Command line from debugger
if(launchDataType == LDT_FROM_DEBUGGER_CMDLINE)
xbox_PrepareArgs((char*)((PLD_FROM_DEBUGGER_CMDLINE)&launchData)->szCmdLine, xargv, xargc);
// Command line from homebrew dashboards (XBMC, etc.)
else if(launchDataType == LDT_TITLE && ((PCUSTOM_LAUNCH_DATA)&launchData)->magic == CUSTOM_LAUNCH_MAGIC)
xbox_PrepareArgs((char*)((PCUSTOM_LAUNCH_DATA)&launchData)->szFilename, xargv, xargc);
// Command line from Agar application (AG_Odalaunch)
else if(launchDataType == LDT_TITLE && ((PAG_LAUNCH_DATA)&launchData)->magic == AG_LAUNCH_MAGIC)
{
xbox_RecordLauncherXBE(((PAG_LAUNCH_DATA)&launchData)->szLauncherXBE, ((PAG_LAUNCH_DATA)&launchData)->dwID);
xbox_PrepareArgs((char*)((PAG_LAUNCH_DATA)&launchData)->szCmdLine, xargv, xargc);
}
}
xbox_MountPartitions();
xbox_InitNet();
if(Xbox_RROD)
xbox_EnableCustomLED();
I_Main(xargc, xargv); // Does not return
}
#endif // _XBOX

View file

@ -1,77 +0,0 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id$
//
// Copyright (C) 2006-2025 by The Odamex Team.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//
// DESCRIPTION:
// Xbox Support
//
//-----------------------------------------------------------------------------
#ifndef _I_XBOX_H
#define _I_XBOX_H
#ifdef _XBOX
#include <SDL.h>
struct hostent
{
char *h_name; /* canonical name of host */
char **h_aliases; /* alias list */
int h_addrtype; /* host address type */
int h_length; /* length of address */
char **h_addr_list; /* list of addresses */
#define h_addr h_addr_list[0]
};
// Xbox function overrides
#undef getenv
#define getenv xbox_Getenv
#undef putenv
#define putenv xbox_Putenv
#undef getcwd
#define getcwd xbox_GetCWD
#undef exit
#define exit xbox_Exit
#undef atexit
#define atexit xbox_AtExit
#define inet_ntoa xbox_InetNtoa
#define gethostbyname xbox_GetHostByName
#define gethostname xbox_GetHostname
// Xbox function override declarations
char *xbox_Getenv(const char *);
int xbox_Putenv(const char *);
char *xbox_GetCWD(char *buf, size_t size);
char *xbox_InetNtoa(struct in_addr in);
struct hostent *xbox_GetHostByName(const char *name);
int xbox_GetHostname(char *name, int namelen);
void xbox_Exit(int status);
void xbox_AtExit(void (*function)(void));
// Print useful memory information for debugging
void xbox_PrintMemoryDebug();
// Write a SaveMeta.xbx file
void xbox_WriteSaveMeta(std::string path, std::string text);
// Get a unique save path for a save slot
std::string xbox_GetSavePath(std::string file, int slot);
#endif // _XBOX
#endif // _I_XBOX_H

View file

@ -1,30 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 8.00
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "odamex", "odamex.vcproj", "{70469239-A02A-4D90-8C58-A1613FCE3F21}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
Debug = Debug
Profile = Profile
Profile_FastCap = Profile_FastCap
Release = Release
Release_LTCG = Release_LTCG
EndGlobalSection
GlobalSection(ProjectConfiguration) = postSolution
{70469239-A02A-4D90-8C58-A1613FCE3F21}.Debug.ActiveCfg = Debug|Xbox
{70469239-A02A-4D90-8C58-A1613FCE3F21}.Debug.Build.0 = Debug|Xbox
{70469239-A02A-4D90-8C58-A1613FCE3F21}.Profile.ActiveCfg = Profile|Xbox
{70469239-A02A-4D90-8C58-A1613FCE3F21}.Profile.Build.0 = Profile|Xbox
{70469239-A02A-4D90-8C58-A1613FCE3F21}.Profile_FastCap.ActiveCfg = Profile_FastCap|Xbox
{70469239-A02A-4D90-8C58-A1613FCE3F21}.Profile_FastCap.Build.0 = Profile_FastCap|Xbox
{70469239-A02A-4D90-8C58-A1613FCE3F21}.Release.ActiveCfg = Release|Xbox
{70469239-A02A-4D90-8C58-A1613FCE3F21}.Release.Build.0 = Release|Xbox
{70469239-A02A-4D90-8C58-A1613FCE3F21}.Release_LTCG.ActiveCfg = Release_LTCG|Xbox
{70469239-A02A-4D90-8C58-A1613FCE3F21}.Release_LTCG.Build.0 = Release_LTCG|Xbox
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection
GlobalSection(ExtensibilityAddIns) = postSolution
EndGlobalSection
EndGlobal

File diff suppressed because it is too large Load diff

View file

@ -42,6 +42,7 @@ if(LibAgar_FOUND)
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION}")
set(MACOSX_BUNDLE_BUNDLE_VERSION "${PROJECT_VERSION}")
set(MACOSX_BUNDLE_ICON_FILE odalaunch.icns)
set(MACOSX_BUNDLE_GUI_IDENTIFIER net.odamex.ag-odalaunch)
if(APPLE)
add_custom_command(

View file

@ -19,13 +19,13 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>11.1.1</string>
<string>12.0.0</string>
<key>CFBundleShortVersionString</key>
<string>11.1.1</string>
<string>12.0.0</string>
<key>CFBundleGetInfoString</key>
<string>Copyright © 2006-2025 The Odamex Team</string>
<key>CFBundleLongVersionString</key>
<string>11.1.1</string>
<string>12.0.0</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2006-2025 The Odamex Team</string>
<key>LSRequiresCarbon</key>

View file

@ -1,4 +1,4 @@
// Emacs style mode select -*- C++ -*-
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id$
@ -42,10 +42,6 @@
#include "typedefs.h"
#include "icons.h"
#ifdef _XBOX
#include "xbox_main.h"
#endif
using namespace std;
namespace agOdalaunch {
@ -64,7 +60,7 @@ AGOL_MainWindow::AGOL_MainWindow(int width, int height) :
ManualDialog(NULL), CloseManualHandler(NULL),
QServer(NULL), WindowExited(false)
{
// Create the Agar window. If we are using a single-window display driver (sdlfb, sdlgl)
// Create the Agar window. If we are using a single-window display driver (sdlfb, sdlgl)
// make the window plain (no window decorations). No flags for multi-window drivers (glx, wgl)
MainWindow = AG_WindowNewNamedS(agDriverSw ? AG_WINDOW_PLAIN : 0, "MainWindow");
AG_WindowSetGeometryAligned(MainWindow, AG_WINDOW_MC, width, height);
@ -89,12 +85,12 @@ AGOL_MainWindow::AGOL_MainWindow(int width, int height) :
AG_WindowMaximize(MainWindow);
// Add the show event
AG_AddEvent(MainWindow, "window-shown", EventReceiver, "%p",
AG_AddEvent(MainWindow, "window-shown", EventReceiver, "%p",
RegisterEventHandler((EVENT_FUNC_PTR)&AGOL_MainWindow::OnShow));
// Set the window close action
AG_WindowSetCloseAction(MainWindow, AG_WINDOW_DETACH);
AG_AddEvent(MainWindow, "window-close", EventReceiver, "%p",
AG_AddEvent(MainWindow, "window-close", EventReceiver, "%p",
RegisterEventHandler((EVENT_FUNC_PTR)&AGOL_MainWindow::ExitWindow));
// Add the save widget states event
@ -121,7 +117,7 @@ AGOL_MainWindow::~AGOL_MainWindow()
{
// If the window exit action has not been performed by this time
// then the driver being used is a single-window driver that does
// not trigger the exit action when the window is closed (due to
// not trigger the exit action when the window is closed (due to
// the fact that the close button is actually for the driver window
// itself.) In that case it should be safe to save the widget states
// because the window is actually still valid. In all other cases
@ -195,51 +191,51 @@ AG_Menu *AGOL_MainWindow::CreateMainMenu(void *parent)
// File menu
m = AG_MenuNode(menu->root, "File", NULL);
AG_MenuAction(m, "Settings", agIconGear.s, EventReceiver, "%p",
AG_MenuAction(m, "Settings", agIconGear.s, EventReceiver, "%p",
RegisterEventHandler((EVENT_FUNC_PTR)&AGOL_MainWindow::OnOpenSettingsDialog));
AG_MenuSeparator(m);
AG_MenuActionKb(m, "Exit", agIconClose.s, AG_KEY_Q, AG_KEYMOD_CTRL,
AG_MenuActionKb(m, "Exit", agIconClose.s, AG_KEY_Q, AG_KEYMOD_CTRL,
EventReceiver, "%p", RegisterEventHandler((EVENT_FUNC_PTR)&AGOL_MainWindow::OnExit));
// Action menu
m = AG_MenuNode(menu->root, "Action", NULL);
AG_MenuAction(m, "Launch", NULL, EventReceiver, "%p",
AG_MenuAction(m, "Launch", NULL, EventReceiver, "%p",
RegisterEventHandler((EVENT_FUNC_PTR)&AGOL_MainWindow::OnLaunch));
AG_MenuAction(m, "Run Offline", NULL, EventReceiver, "%p",
AG_MenuAction(m, "Run Offline", NULL, EventReceiver, "%p",
RegisterEventHandler((EVENT_FUNC_PTR)&AGOL_MainWindow::OnOfflineLaunch));
AG_MenuSeparator(m);
AG_MenuAction(m, "Refresh Selected", NULL, EventReceiver, "%p",
AG_MenuAction(m, "Refresh Selected", NULL, EventReceiver, "%p",
RegisterEventHandler((EVENT_FUNC_PTR)&AGOL_MainWindow::OnRefreshSelected));
AG_MenuAction(m, "Refresh All", NULL, EventReceiver, "%p",
AG_MenuAction(m, "Refresh All", NULL, EventReceiver, "%p",
RegisterEventHandler((EVENT_FUNC_PTR)&AGOL_MainWindow::OnRefreshAll));
AG_MenuAction(m, "Get Master List", NULL, EventReceiver, "%p",
AG_MenuAction(m, "Get Master List", NULL, EventReceiver, "%p",
RegisterEventHandler((EVENT_FUNC_PTR)&AGOL_MainWindow::OnGetMasterList));
// Tools Menu
m = AG_MenuNode(menu->root, "Tools", NULL);
m = AG_MenuNode(m, "OdaGet", NULL);
AG_MenuDisable(m);
AG_MenuAction(m, "Get WAD", NULL, EventReceiver, "%p",
AG_MenuAction(m, "Get WAD", NULL, EventReceiver, "%p",
RegisterEventHandler((EVENT_FUNC_PTR)&AGOL_MainWindow::OnGetWAD));
AG_MenuAction(m, "Configure", NULL, EventReceiver, "%p",
AG_MenuAction(m, "Configure", NULL, EventReceiver, "%p",
RegisterEventHandler((EVENT_FUNC_PTR)&AGOL_MainWindow::OnOdaGetConfig));
AG_MenuEnable(m);
// Advanced menu
m = AG_MenuNode(menu->root, "Advanced", NULL);
AG_MenuAction(m, "Manual Connect", NULL, EventReceiver, "%p",
AG_MenuAction(m, "Manual Connect", NULL, EventReceiver, "%p",
RegisterEventHandler((EVENT_FUNC_PTR)&AGOL_MainWindow::OnManualConnect));
AG_MenuDisable(m);
AG_MenuAction(m, "Custom Servers", NULL, EventReceiver, "%p",
AG_MenuAction(m, "Custom Servers", NULL, EventReceiver, "%p",
RegisterEventHandler((EVENT_FUNC_PTR)&AGOL_MainWindow::OnCustomServer));
AG_MenuEnable(m);
// Help menu
m = AG_MenuNode(menu->root, "Help", NULL);
AG_MenuAction(m, "Report Bug", NULL, EventReceiver, "%p",
AG_MenuAction(m, "Report Bug", NULL, EventReceiver, "%p",
RegisterEventHandler((EVENT_FUNC_PTR)&AGOL_MainWindow::OnReportBug));
AG_MenuSeparator(m);
AG_MenuAction(m, "About", NULL, EventReceiver, "%p",
AG_MenuAction(m, "About", NULL, EventReceiver, "%p",
RegisterEventHandler((EVENT_FUNC_PTR)&AGOL_MainWindow::OnAbout));
return menu;
@ -253,30 +249,30 @@ ODA_ButtonBox *AGOL_MainWindow::CreateMainButtonBox(void *parent)
bbox->buttonbox = AG_BoxNewHoriz(parent, AG_BOX_HFILL);
bbox->launch = CreateButton(bbox->buttonbox, "Launch", odalaunchico,
bbox->launch = CreateButton(bbox->buttonbox, "Launch", odalaunchico,
sizeof(odalaunchico), (EVENT_FUNC_PTR)&AGOL_MainWindow::OnLaunch);
bbox->qlaunch = CreateButton(bbox->buttonbox, "Quick Launch", odaqlaunchico,
bbox->qlaunch = CreateButton(bbox->buttonbox, "Quick Launch", odaqlaunchico,
sizeof(odaqlaunchico), (EVENT_FUNC_PTR)&AGOL_MainWindow::OnOfflineLaunch);
AG_SeparatorNewVert(bbox->buttonbox);
bbox->refresh = CreateButton(bbox->buttonbox, "Refresh Selected", btnrefreshico,
bbox->refresh = CreateButton(bbox->buttonbox, "Refresh Selected", btnrefreshico,
sizeof(btnrefreshico), (EVENT_FUNC_PTR)&AGOL_MainWindow::OnRefreshSelected);
bbox->refreshall = CreateButton(bbox->buttonbox, "Refresh All", btnrefreshallico,
bbox->refreshall = CreateButton(bbox->buttonbox, "Refresh All", btnrefreshallico,
sizeof(btnrefreshico), (EVENT_FUNC_PTR)&AGOL_MainWindow::OnRefreshAll);
bbox->mlist = CreateButton(bbox->buttonbox, "Query Master", btnlistico,
bbox->mlist = CreateButton(bbox->buttonbox, "Query Master", btnlistico,
sizeof(btnlistico), (EVENT_FUNC_PTR)&AGOL_MainWindow::OnGetMasterList);
AG_SeparatorNewVert(bbox->buttonbox);
bbox->settings = CreateButton(bbox->buttonbox, "Settings", btnsettingsico,
bbox->settings = CreateButton(bbox->buttonbox, "Settings", btnsettingsico,
sizeof(btnsettingsico), (EVENT_FUNC_PTR)&AGOL_MainWindow::OnOpenSettingsDialog);
bbox->about = CreateButton(bbox->buttonbox, "About", btnhelpico,
bbox->about = CreateButton(bbox->buttonbox, "About", btnhelpico,
sizeof(btnhelpico), (EVENT_FUNC_PTR)&AGOL_MainWindow::OnAbout);
AG_SeparatorNewVert(bbox->buttonbox);
bbox->exit = CreateButton(bbox->buttonbox, "Exit", btnexitico,
bbox->exit = CreateButton(bbox->buttonbox, "Exit", btnexitico,
sizeof(btnexitico), (EVENT_FUNC_PTR)&AGOL_MainWindow::OnExit);
return bbox;
@ -315,13 +311,13 @@ AG_Table *AGOL_MainWindow::CreateServerList(void *parent)
ostringstream colSzSpec[8];
int colW[8] = { 200, 33, 48, 100, 47, 105, 72, 125 };
list = AG_TableNewPolled(parent, AG_TABLE_EXPAND, EventReceiver, "%p",
list = AG_TableNewPolled(parent, AG_TABLE_EXPAND, EventReceiver, "%p",
RegisterEventHandler((EVENT_FUNC_PTR)&AGOL_MainWindow::UpdateServerList));
AG_TableSetRowDblClickFn(list, EventReceiver, "%p",
AG_TableSetRowDblClickFn(list, EventReceiver, "%p",
RegisterEventHandler((EVENT_FUNC_PTR)&AGOL_MainWindow::OnLaunch));
AG_SetEvent(list, "row-selected", EventReceiver, "%p",
AG_SetEvent(list, "row-selected", EventReceiver, "%p",
RegisterEventHandler((EVENT_FUNC_PTR)&AGOL_MainWindow::OnServerListRowSelected));
// Configure each columns size spec
@ -350,7 +346,7 @@ AG_Table *AGOL_MainWindow::CreateServerList(void *parent)
AG_TableAddCol(list, "Address : Port", colSzSpec[7].str().c_str(), NULL);
// Add an update event that we can schedule without enabling polling
AG_SetEvent(list, "update-items", EventReceiver, "%p",
AG_SetEvent(list, "update-items", EventReceiver, "%p",
RegisterEventHandler((EVENT_FUNC_PTR)&AGOL_MainWindow::UpdateServerList));
return list;
@ -437,8 +433,8 @@ void AGOL_MainWindow::UpdateStatusbarMasterPing(uint64_t ping)
AG_LabelText(MainStatusbar->mping, "Master Ping: %lu", ping);
}
AG_Button *AGOL_MainWindow::CreateButton(void *parent, const char *label,
const unsigned char *icon, int iconsize,
AG_Button *AGOL_MainWindow::CreateButton(void *parent, const char *label,
const unsigned char *icon, int iconsize,
EVENT_FUNC_PTR handler)
{
AG_Button *button;
@ -446,7 +442,7 @@ AG_Button *AGOL_MainWindow::CreateButton(void *parent, const char *label,
button = AG_ButtonNewFn(parent, 0, label, EventReceiver, "%p", RegisterEventHandler(handler));
AG_SetEvent(button, "button-mouseoverlap", EventReceiver, "%p",
AG_SetEvent(button, "button-mouseoverlap", EventReceiver, "%p",
RegisterEventHandler((EVENT_FUNC_PTR)&AGOL_MainWindow::OnMouseOverWidget));
@ -539,7 +535,7 @@ int AGOL_MainWindow::GetServerListRowFromAddr(const string &address)
string cellAddr;
cellAddr = GetAddrFromServerListRow(row);
if(!cellAddr.size())
continue;
@ -616,12 +612,12 @@ void AGOL_MainWindow::UpdatePlayerList(int serverNdx)
AG_Surface *(*teamFn)(void*,int,int) = NullSurfFn;
AG_Surface *(*specFn)(void*,int,int) = NullSurfFn;
string name = " ";
if(QServer[serverNdx].Info.Players[i].Name.size())
name = QServer[serverNdx].Info.Players[i].Name;
// Team pixmap
if(QServer[serverNdx].Info.GameType == GT_TeamDeathmatch ||
if(QServer[serverNdx].Info.GameType == GT_TeamDeathmatch ||
QServer[serverNdx].Info.GameType == GT_CaptureTheFlag)
{
switch(QServer[serverNdx].Info.Players[i].Team)
@ -644,7 +640,7 @@ void AGOL_MainWindow::UpdatePlayerList(int serverNdx)
}
AG_TableAddRow(PlayerList, "%[FS]:%s:%u:%u:%i:%u:%u:%[FS]",
specFn, name.c_str(),
specFn, name.c_str(),
QServer[serverNdx].Info.Players[i].Ping,
QServer[serverNdx].Info.Players[i].Time,
QServer[serverNdx].Info.Players[i].Frags,
@ -895,7 +891,7 @@ void AGOL_MainWindow::AutoSizeTableColumn(AG_Table *table, int col)
if(cell && cell->data.s)
{
int txtsize;
AG_TextSize(cell->data.s, &txtsize, NULL);
if(txtsize > maxpx)
@ -1181,7 +1177,7 @@ void AGOL_MainWindow::UpdateServerList(AG_Event *event)
}
GuiConfig::Read("ShowBlockedServers", showBlocked);
for(size_t i = 0; i < serverCount; ++i)
{
AG_Surface *(*padlockFn)(void*,int,int) = NullSurfFn;
@ -1194,7 +1190,7 @@ void AGOL_MainWindow::UpdateServerList(AG_Event *event)
string gametype;
size_t wadCnt = 0;
int row;
// If we can't immediately get a lock on this server
// move on to the next one.
if(QServer[i].TryLock())
@ -1341,13 +1337,6 @@ void *AGOL_MainWindow::GetMasterList(void *arg)
uint16_t port = 0;
unsigned int masterTimeout;
#ifdef _XBOX
// A slight delay is required to complete initialization on Xbox
// if this is the "Master On Start" query - 3/4 sec
if(StartupQuery)
AG_Delay(750);
#endif
if(GuiConfig::Read("MasterTimeout", masterTimeout) || masterTimeout == 0)
masterTimeout = 500;
@ -1357,15 +1346,11 @@ void *AGOL_MainWindow::GetMasterList(void *arg)
MServer.SetSocket(&socket);
// Get a list of servers
#ifdef _XBOX
MServer.QueryMasters(masterTimeout, 0, 2); // TODO: Make broadcast and retry configurable
#else
MServer.QueryMasters(masterTimeout, 1, 2); // TODO: Make broadcast and retry configurable
#endif
serverCount = MServer.GetServerCount();
// If there are no servers something went wrong
// If there are no servers something went wrong
// (either with the query or with the Odamex project ;P)
if(serverCount == 0)
{
@ -1438,10 +1423,6 @@ void *AGOL_MainWindow::QueryAllServers(void *arg)
if(serverCount == 0)
return NULL;
#ifdef _XBOX
Xbox::EnableJoystickUpdates(false);
#endif
StartServerListPoll();
ClearList(PlayerList);
@ -1478,12 +1459,6 @@ void *AGOL_MainWindow::QueryAllServers(void *arg)
serversQueried++;
}
}
#ifdef _XBOX
// This yield is required on Xbox. Without it the Xbox sometimes fails to give the other
// threads CPU time and that results in an unacceptably long query and an interface pause
// while this thread continuously queries the other threads for completion. -- Hyper_Eye
AG_Delay(1); // 1ms yield
#endif
UpdateQueriedLabelCompleted(static_cast<int>(count));
}
@ -1498,10 +1473,6 @@ void *AGOL_MainWindow::QueryAllServers(void *arg)
UpdatePlayerList(selectedNdx);
UpdateServInfoList(selectedNdx);
#ifdef _XBOX
Xbox::EnableJoystickUpdates(true);
#endif
return NULL;
}
@ -1524,10 +1495,10 @@ int AGOL_MainWindow::CellCompare(const void *p1, const void *p2)
AG_TableCell *c2 = (AG_TableCell*)p2;
// Make sure the cells are the same type
if (c1->type != c2->type || strcmp(c1->fmt, c2->fmt) != 0)
if (c1->type != c2->type || strcmp(c1->fmt, c2->fmt) != 0)
{
// See if one of the cells is null
if (c1->type == AG_CELL_NULL || c2->type == AG_CELL_NULL)
if (c1->type == AG_CELL_NULL || c2->type == AG_CELL_NULL)
{
// Sort out the null (unset) cells
return (c1->type == AG_CELL_NULL ? 1 : -1);
@ -1576,7 +1547,7 @@ int AGOL_MainWindow::CellCompare(const void *p1, const void *p2)
{
compval[0] = 1;
}
if(c2->fnSu == BulletBlueSurfFn ||
c2->fnSu == SpectatorIconSurfFn ||
c2->fnSu == PadlockIconSurfFn)

View file

@ -1,4 +1,4 @@
// Emacs style mode select -*- C++ -*-
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id$
@ -27,10 +27,6 @@
#include <string>
#include <memory>
#ifdef _XBOX
#include <xtl.h>
#endif
#include <agar/core.h>
#include <agar/gui.h>
@ -86,9 +82,7 @@ int GameCommand::Launch()
cmd += AG_PATHSEP;
// Add the bin to the path
#ifdef _XBOX
cmd += "odamex.xbe";
#elif _WIN32
#ifdef _WIN32
cmd += "odamex.exe";
#else
cmd += "odamex";
@ -96,7 +90,7 @@ int GameCommand::Launch()
// The path with bin tacked on is the first arg
argv[0] = strdup(cmd.c_str());
// Add each param as an arg
for(i = Parameters.begin(); i != Parameters.end(); ++i, ++argc)
argv[argc] = strdup((*i).c_str());

View file

@ -1,4 +1,4 @@
// Emacs style mode select -*- C++ -*-
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id$
@ -41,10 +41,6 @@
#include "agar_mutex_factory.h"
#include "threads/mutex_factory.h"
#ifdef _XBOX
#include "xbox_main.h"
#endif
using namespace std;
using namespace odalpapi;
@ -80,20 +76,12 @@ int AGOL_InitVideo(const string& drivers, const int width, const int height, con
spec << "(width=" << width << ":height=" << height << ":depth=" << depth << ")";
if (AG_InitGraphics(spec.str().c_str()) == -1)
if (AG_InitGraphics(spec.str().c_str()) == -1)
{
cerr << AG_GetError() << endl;
return -1;
}
#ifdef _XBOX
// Software cursor only updates at the refresh rate so make it respectable
if(agDriverSw)
{
AG_SetRefreshRate(60);
}
#endif
// Pick up GUI subsystem options
GuiConfig::Load();
@ -117,7 +105,7 @@ int main(int argc, char *argv[])
int width, height;
/* Initialize Agar-Core. */
if (AG_InitCore("ag-odalaunch", AG_VERBOSE | AG_CREATE_DATADIR) == -1)
if (AG_InitCore("ag-odalaunch", AG_VERBOSE | AG_CREATE_DATADIR) == -1)
{
cerr << AG_GetError() << endl;
return (-1);
@ -126,9 +114,9 @@ int main(int argc, char *argv[])
// Initial config load
GuiConfig::Load();
while ((c = AG_Getopt(argc, argv, "?d:f", &optArg, NULL)) != -1)
while ((c = AG_Getopt(argc, argv, "?d:f", &optArg, NULL)) != -1)
{
switch (c)
switch (c)
{
case 'd':
drivers = optArg;
@ -170,13 +158,6 @@ int main(int argc, char *argv[])
if(!drivers.size())
{
GuiConfig::Read("VideoDriver", drivers);
#ifdef _XBOX
if(!drivers.size())
{
drivers = "sdlfb";
}
#endif
}
if(AGOL_InitVideo(drivers, width, height, 32))
@ -198,11 +179,6 @@ int main(int argc, char *argv[])
AG_BindGlobalKey(AG_KEY_F12, AG_KEYMOD_ANY, AGOL_StartDebugger);
#endif
#ifdef _XBOX
// Initialize the Xbox controller
Xbox::InitializeJoystick();
#endif
// Event (main) Loop
AG_EventLoop();

View file

@ -9,24 +9,12 @@ set -x
# Install packages
sudo apt update
if [[ -z ${USE_SDL12:-} ]]; then
sudo apt install ninja-build libsdl2-dev libsdl2-mixer-dev \
libcurl4-openssl-dev libpng-dev libwxgtk3.2-dev deutex
else
sudo apt install ninja-build libsdl1.2-dev libsdl-mixer1.2-dev \
libcurl4-openssl-dev libpng-dev libwxgtk3.2-dev deutex
fi
sudo apt install ninja-build libsdl2-dev libsdl2-mixer-dev \
libcurl4-openssl-dev libpng-dev libwxgtk3.2-dev deutex
# Generate build
mkdir -p build && cd build
if [[ -z ${USE_SDL12:-} ]]; then
cmake .. -GNinja \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DBUILD_OR_FAIL=1 -DBUILD_CLIENT=1 -DBUILD_SERVER=1 \
-DBUILD_MASTER=1 -DBUILD_LAUNCHER=1
else
cmake .. -GNinja \
-DCMAKE_BUILD_TYPE=RelWithDebInfo -DUSE_SDL12=1 \
-DBUILD_OR_FAIL=1 -DBUILD_CLIENT=1 -DBUILD_SERVER=1 \
-DBUILD_MASTER=1 -DBUILD_LAUNCHER=1
fi
cmake .. -GNinja \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DBUILD_OR_FAIL=1 -DBUILD_CLIENT=1 -DBUILD_SERVER=1 \
-DBUILD_MASTER=1 -DBUILD_LAUNCHER=1

View file

@ -170,16 +170,16 @@ function ZipDebugX64 {
# Copy pdb files into zip. DO NOT THROW THESE AWAY!
Copy-Item -Force -Path `
"${CurrentDir}\BuildX64\client\RelWithDebInfo\odamex.pdb" `
-Destination "${OutputDir}\odamex-x64-${OdamexVersion}.pdb"
-Destination "${OutputDir}\odamex-x64-${OdamexVersion}${OdamexTestSuffix}.pdb"
Copy-Item -Force -Path `
"${CurrentDir}\BuildX64\server\RelWithDebInfo\odasrv.pdb" `
-Destination "${OutputDir}\odasrv-x64-${OdamexVersion}.pdb"
-Destination "${OutputDir}\odasrv-x64-${OdamexVersion}${OdamexTestSuffix}.pdb"
Copy-Item -Force -Path `
"${CurrentDir}\BuildX64\odalaunch\RelWithDebInfo\odalaunch.pdb" `
-Destination "${OutputDir}\odalaunch-x64-${OdamexVersion}.pdb"
-Destination "${OutputDir}\odalaunch-x64-${OdamexVersion}${OdamexTestSuffix}.pdb"
7z.exe a `
"${PdbDir}\odamex-debug-pdb-${OdamexVersion}-x64.zip" `
"${PdbDir}\odamex-debug-pdb-${OdamexVersion}${OdamexTestSuffix}-x64.zip" `
"${OutputDir}\*.pdb"
Remove-Item -Force -Path "${OutputDir}\*.pdb"

View file

@ -168,16 +168,16 @@ function ZipDebugX86 {
# Copy pdb files into zip. DO NOT THROW THESE AWAY!
Copy-Item -Force -Path `
"${CurrentDir}\BuildX86\client\RelWithDebInfo\odamex.pdb" `
-Destination "${OutputDir}\odamex-x86-${OdamexVersion}.pdb"
-Destination "${OutputDir}\odamex-x86-${OdamexVersion}${OdamexTestSuffix}.pdb"
Copy-Item -Force -Path `
"${CurrentDir}\BuildX86\server\RelWithDebInfo\odasrv.pdb" `
-Destination "${OutputDir}\odasrv-x86-${OdamexVersion}.pdb"
-Destination "${OutputDir}\odasrv-x86-${OdamexVersion}${OdamexTestSuffix}.pdb"
Copy-Item -Force -Path `
"${CurrentDir}\BuildX86\odalaunch\RelWithDebInfo\odalaunch.pdb" `
-Destination "${OutputDir}\odalaunch-x86-${OdamexVersion}.pdb"
-Destination "${OutputDir}\odalaunch-x86-${OdamexVersion}${OdamexTestSuffix}.pdb"
7z.exe a `
"${PdbDir}\odamex-debug-pdb-${OdamexVersion}-x86.zip" `
"${PdbDir}\odamex-debug-pdb-${OdamexVersion}${OdamexTestSuffix}-x86.zip" `
"${OutputDir}\*.pdb"
Remove-Item -Force -Path "${OutputDir}\*.pdb"

View file

@ -3,7 +3,10 @@ Set-PSDebug -Trace 1
mkdir "build-x32" | Out-Null
Set-Location "build-x32"
& cmake .. `
-G "Visual Studio 17 2022" -A Win32 -DBUILD_ODALAUNCH=0 `
& cmake .. -G "Visual Studio 17 2022" `
-A Win32 `
-DBUILD_OR_FAIL=1 `
-DBUILD_CLIENT=1 -DBUILD_SERVER=1 `
-DBUILD_MASTER=1 -DBUILD_LAUNCHER=1
Set-Location ..

View file

@ -29,10 +29,6 @@ if (GCONSOLE)
file(GLOB CLIENT_HEADERS ${CLIENT_HEADERS} switch/*.h)
file(GLOB CLIENT_SOURCES ${CLIENT_SOURCES} switch/*.cpp)
odamex_target_settings_nx(CLIENT_DIR GLOB)
elseif (VWII)
set(CLIENT_DIR ${CLIENT_DIR} vwii) # Nintendo Wii/vWII
file(GLOB CLIENT_HEADERS ${CLIENT_HEADERS} vwii/*.h)
file(GLOB CLIENT_SOURCES ${CLIENT_SOURCES} vwii/*.cpp)
endif()
endif()
@ -205,7 +201,7 @@ if(TARGET SDL2::SDL2 OR TARGET SDL::SDL)
endif()
target_link_libraries(odamex SDL2::mixer)
endif()
target_link_libraries(odamex ${PNG_LIBRARY} ${ZLIB_LIBRARY} CURL::libcurl)
if(NOT GCONSOLE)
target_include_directories(odamex PRIVATE gui)
if(USE_INTERNAL_FLTK)
@ -224,13 +220,11 @@ if(TARGET SDL2::SDL2 OR TARGET SDL::SDL)
target_link_libraries(odamex PkgConfig::JSONCPP)
endif()
target_link_libraries(odamex libADLMIDI::ADLMIDI_static)
if(ENABLE_PORTMIDI)
target_link_libraries(odamex ${PORTMIDI_LIBRARY})
endif()
target_link_libraries(odamex ZLIB::ZLIB PNG::PNG fmt::fmt minilzo cpptrace::cpptrace)
target_link_libraries(odamex ZLIB::ZLIB PNG::PNG fmt::fmt minilzo cpptrace::cpptrace libADLMIDI::ADLMIDI_static curl_interface)
if(WIN32)
target_link_libraries(odamex winmm wsock32 shlwapi)
@ -238,10 +232,6 @@ if(TARGET SDL2::SDL2 OR TARGET SDL::SDL)
target_link_libraries(odamex ${APPLE_FRAMEWORKS})
elseif(NSWITCH)
target_link_libraries(odamex SDL2 mpg123 modplug vorbisfile vorbis opusfile opus ogg EGL glapi drm_nouveau nx m)
elseif(VWII)
# Ch0wW : this is UGLY, please fix it ASAP !!
target_link_libraries(odamex -L$ENV{DEVKITPRO}/libogc/lib/wii -L$ENV{DEVKITPRO}/portlibs/ppc/lib -L$ENV{DEVKITPRO}/portlibs/wii/lib)
target_link_libraries(odamex SDL_mixer SDL smpeg png png16 vorbisidec z fat wiiuse bte ogc ogg m wiikeyboard)
elseif(SOLARIS)
target_link_libraries(odamex socket nsl)
endif()
@ -262,6 +252,7 @@ if(TARGET SDL2::SDL2 OR TARGET SDL::SDL)
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION}")
set(MACOSX_BUNDLE_BUNDLE_VERSION "${PROJECT_VERSION}")
set(MACOSX_BUNDLE_ICON_FILE odamex.icns)
set(MACOSX_BUNDLE_GUI_IDENTIFIER net.odamex.odamex)
if(APPLE)
add_custom_command(
@ -324,10 +315,6 @@ if(TARGET SDL2::SDL2 OR TARGET SDL::SDL)
endif()
elseif(NSWITCH)
odamex_target_postcompile_nx(odamex)
elseif(VWII)
message(${CMAKE_BINARY_DIR})
add_custom_command( TARGET odamex POST_BUILD
COMMAND elf2dol ${CMAKE_BINARY_DIR}/client/odamex ${CMAKE_BINARY_DIR}/boot.dol )
elseif(WIN32)
install(TARGETS odamex
RUNTIME DESTINATION .

View file

@ -569,12 +569,6 @@ class BootWindow : public Fl_Window
scannedIWAD_t iwad = m_IWADs[value - 1];
g_SelectedWADs.iwad = iwad.path;
if (iwad.id != NULL && iwad.id->mIdName == "CHEX QUEST")
{
g_SelectedWADs.options.push_back("-deh");
g_SelectedWADs.options.push_back("chex.deh");
}
// PWADs
for (const auto& pwad : m_selectedPWADs)
{

View file

@ -28,7 +28,7 @@
#include "gui_resource.h"
#if defined(_WIN32) && !defined(_XBOX)
#if defined(_WIN32)
#include "FL/x.H"
#include "win32inc.h"

View file

@ -42,15 +42,11 @@
#include "i_system.h"
#include "hu_stuff.h"
#ifdef _XBOX
#include "i_xbox.h"
#elif __SWITCH__
#ifdef __SWITCH__
#include "nx_io.h"
#endif
#if defined(SDL12)
#include "i_input_sdl12.h"
#elif defined(SDL20)
#if defined(SDL20)
#include "i_input_sdl20.h"
#endif
@ -594,9 +590,7 @@ bool I_InitInput()
atterm(I_ShutdownInput);
#if defined(SDL12)
input_subsystem = new ISDL12InputSubsystem();
#elif defined(SDL20)
#ifdef SDL20
input_subsystem = new ISDL20InputSubsystem();
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,188 +0,0 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id$
//
// Copyright (C) 2006-2025 by The Odamex Team.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
//
//
//-----------------------------------------------------------------------------
#pragma once
#include "i_sdl.h"
#include "i_input.h"
#include "d_event.h"
#include <queue>
#include <list>
#include "hashtable.h"
typedef OHashTable<int, int> KeyTranslationTable;
#ifdef SDL12
// ============================================================================
//
// ISDL12KeyboardInputDevice class interface
//
// ============================================================================
class ISDL12KeyboardInputDevice : public IKeyboardInputDevice
{
public:
ISDL12KeyboardInputDevice(int id);
virtual ~ISDL12KeyboardInputDevice();
virtual bool active() const;
virtual void pause();
virtual void resume();
virtual void reset();
virtual void gatherEvents();
virtual bool hasEvent() const
{ return !mEvents.empty(); }
virtual void getEvent(event_t* ev);
virtual void flushEvents();
private:
int translateKey(SDL_keysym keysym);
bool mActive;
typedef std::queue<event_t> EventQueue;
EventQueue mEvents;
};
// ============================================================================
//
// ISDL12MouseInputDevice class interface
//
// ============================================================================
class ISDL12MouseInputDevice : public IInputDevice
{
public:
ISDL12MouseInputDevice(int id);
virtual ~ISDL12MouseInputDevice();
virtual bool active() const;
virtual void pause();
virtual void resume();
virtual void reset();
virtual void gatherEvents();
virtual bool hasEvent() const
{ return !mEvents.empty(); }
virtual void getEvent(event_t* ev);
virtual void flushEvents();
private:
void center();
bool mActive;
typedef std::queue<event_t> EventQueue;
EventQueue mEvents;
};
// ============================================================================
//
// ISDL12JoystickInputDevice class interface
//
// ============================================================================
class ISDL12JoystickInputDevice : public IInputDevice
{
public:
ISDL12JoystickInputDevice(int id);
virtual ~ISDL12JoystickInputDevice();
virtual bool active() const;
virtual void pause();
virtual void resume();
virtual void reset();
virtual void gatherEvents();
virtual bool hasEvent() const
{ return !mEvents.empty(); }
virtual void getEvent(event_t* ev);
virtual void flushEvents();
private:
static const int JOY_DEADZONE = 6000;
bool mActive;
typedef std::queue<event_t> EventQueue;
EventQueue mEvents;
int mJoystickId;
SDL_Joystick* mJoystick;
int mNumHats;
int* mHatStates;
};
// ============================================================================
//
// ISDL12InputSubsystem class interface
//
// ============================================================================
class ISDL12InputSubsystem : public IInputSubsystem
{
public:
ISDL12InputSubsystem();
virtual ~ISDL12InputSubsystem();
virtual void grabInput();
virtual void releaseInput();
virtual bool isInputGrabbed() const
{ return mInputGrabbed; }
virtual std::vector<IInputDeviceInfo> getKeyboardDevices() const;
virtual void initKeyboard(int id);
virtual void shutdownKeyboard(int id);
virtual std::vector<IInputDeviceInfo> getMouseDevices() const;
virtual void initMouse(int id);
virtual void shutdownMouse(int id);
virtual std::vector<IInputDeviceInfo> getJoystickDevices() const;
virtual void initJoystick(int id);
virtual void shutdownJoystick(int id);
private:
bool mInputGrabbed;
};
#endif // SDL12

View file

@ -433,13 +433,24 @@ void ISDL20MouseInputDevice::resume()
{
mActive = true;
reset();
// [RV] Always use relative mouse mode and
// force unscaled relative motion across supported SDL versions
SDL_SetRelativeMouseMode(SDL_TRUE);
#if SDL_VERSION_ATLEAST(2, 0, 14)
SDL_SetHintWithPriority(SDL_HINT_MOUSE_RELATIVE_SCALING, "0", SDL_HINT_OVERRIDE);
#endif
#if SDL_VERSION_ATLEAST(2, 26, 0)
SDL_SetHintWithPriority(SDL_HINT_MOUSE_RELATIVE_SYSTEM_SCALE, "0", SDL_HINT_OVERRIDE);
#endif
SDL_EventState(SDL_MOUSEMOTION, SDL_ENABLE);
SDL_EventState(SDL_MOUSEBUTTONDOWN, SDL_ENABLE);
SDL_EventState(SDL_MOUSEBUTTONUP, SDL_ENABLE);
}
//
// ISDL20MouseInputDevice::gatherEvents
//

View file

@ -25,17 +25,6 @@
#include "odamex.h"
// denis - todo - remove
#include "win32inc.h"
#ifdef _WIN32
#ifndef _XBOX
#undef GetMessage
typedef bool (WINAPI *SetAffinityFunc)(HANDLE hProcess, DWORD mask);
#endif // !_XBOX
#else
#include <sched.h>
#endif // WIN32
#ifdef UNIX
// for getuid and geteuid
#include <unistd.h>
@ -64,10 +53,6 @@
#include "c_console.h"
#include "z_zone.h"
#ifdef _XBOX
#include "i_xbox.h"
#endif
// Use main() on windows for msvc
#if defined(_MSC_VER) && !defined(GCONSOLE)
# pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
@ -171,81 +156,21 @@ int main(int argc, char *argv[])
if(argc == 2 && argv && argv[1])
{
static constexpr std::string_view protocol = "odamex://";
const char *uri = argv[1];
std::string_view uri = argv[1];
if(protocol == uri)
if(uri.substr(0, protocol.length()) == protocol)
{
std::string location = uri + protocol.length();
std::string_view location = uri.substr(protocol.length());
size_t term = location.find_first_of('/');
if(term == std::string::npos)
term = location.length();
Args.AppendArg("-connect");
Args.AppendArg(location.substr(0, term).c_str());
Args.AppendArg(std::string(location.substr(0, term)).c_str());
}
}
#if defined(SDL12)
// [Russell] - No more double-tapping of capslock to enable autorun
SDL_putenv((char*)"SDL_DISABLE_LOCK_KEYS=1");
// Set SDL video centering
SDL_putenv((char*)"SDL_VIDEO_WINDOW_POS=center");
SDL_putenv((char*)"SDL_VIDEO_CENTERED=1");
#endif
#if defined _WIN32 && !defined _XBOX
#if defined(SDL12)
// From the SDL 1.2.10 release notes:
//
// > The "windib" video driver is the default now, to prevent
// > problems with certain laptops, 64-bit Windows, and Windows
// > Vista.
//
// The hell with that.
// SoM: the gdi interface is much faster for windowed modes which are more
// commonly used. Thus, GDI is default.
//
// GDI mouse issues fill many users with great sadness. We are going back
// to directx as defulat for now and the people will rejoice. --Hyper_Eye
if (Args.CheckParm ("-gdi"))
putenv((char*)"SDL_VIDEODRIVER=windib");
else
putenv((char*)"SDL_VIDEODRIVER=directx");
#endif // SDL12
// Set the process affinity mask to 1 on Windows, so that all threads
// run on the same processor. This is a workaround for a bug in
// SDL_mixer that causes occasional crashes. Thanks to entryway and fraggle for this.
//
// [ML] 8/6/10: Updated to match prboom+'s I_SetAffinityMask. We don't do everything
// you might find in there but we do enough for now.
HMODULE kernel32_dll = LoadLibrary("kernel32.dll");
if (kernel32_dll)
{
SetAffinityFunc SetAffinity = (SetAffinityFunc)GetProcAddress(kernel32_dll, "SetProcessAffinityMask");
if (SetAffinity)
{
if (!SetAffinity(GetCurrentProcess(), 1))
LOG << "Failed to set process affinity mask: " << GetLastError() << std::endl;
}
}
#endif // _WIN32 && !_XBOX
#ifdef X11
#if defined(SDL12)
// [SL] 2011-12-21 - Ensure we're getting raw DGA mouse input from X11,
// bypassing X11's mouse acceleration
putenv((char*)"SDL_VIDEO_X11_DGAMOUSE=1");
#endif // SDL12
#endif // X11
unsigned int sdl_flags = SDL_INIT_TIMER;
#ifdef _MSC_VER

View file

@ -387,7 +387,7 @@ static std::list<MidiEvent*> *I_ReadMidiTrack(MEMFILE *mf)
if (chunkheader.chunk_id != cTrackChunkId)
{
Printf(PRINT_WARNING, "I_ReadMidiTrack: Unexpected chunk header ID\n");
PrintFmt(PRINT_WARNING, "I_ReadMidiTrack: Unexpected chunk header ID\n");
return NULL;
}
@ -400,7 +400,7 @@ static std::list<MidiEvent*> *I_ReadMidiTrack(MEMFILE *mf)
if (!newevent)
{
Printf(PRINT_WARNING, "I_ReadMidiTrack: Unable to read MIDI event\n");
PrintFmt(PRINT_WARNING, "I_ReadMidiTrack: Unable to read MIDI event\n");
I_ClearMidiEventList(eventlist);
delete eventlist;
@ -484,7 +484,7 @@ void MidiSong::_ParseSong(MEMFILE *mf)
if (chunkheader.chunk_id != cHeaderChunkId)
{
Printf(PRINT_WARNING, "MidiSong::_ParseSong: Unexpected file header ID\n");
PrintFmt(PRINT_WARNING, "MidiSong::_ParseSong: Unexpected file header ID\n");
return;
}
@ -499,7 +499,7 @@ void MidiSong::_ParseSong(MEMFILE *mf)
if (fileheader.format_type != 0 && fileheader.format_type != 1)
{
Printf(PRINT_WARNING, "MidiSong::_ParseSong: Only type 0 or type 1 MIDI files are supported.\n");
PrintFmt(PRINT_WARNING, "MidiSong::_ParseSong: Only type 0 or type 1 MIDI files are supported.\n");
return;
}
@ -509,7 +509,7 @@ void MidiSong::_ParseSong(MEMFILE *mf)
std::list<MidiEvent*> *eventlist = I_ReadMidiTrack(mf);
if (!eventlist)
{
Printf(PRINT_WARNING, "MidiSong::_ParseSong: Error reading track %lu.\n", i + 1);
PrintFmt(PRINT_WARNING, "MidiSong::_ParseSong: Error reading track {}.\n", i + 1);
return;
}

View file

@ -1,4 +1,4 @@
// Emacs style mode select -*- C++ -*-
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id$
@ -26,18 +26,6 @@
#include <list>
#include "m_memio.h"
static byte gm_system_on[] = {
0xF0, 0x7E, 0x7F, 0x09, 0x01, 0xF7
};
static byte gs_reset[] = {
0xF0, 0x41, 0x10, 0x42, 0x12, 0x40, 0x00, 0x7F, 0x00, 0x41, 0xF7
};
static byte xg_system_on[] = {
0xF0, 0x43, 0x10, 0x4C, 0x00, 0x00, 0x7E, 0x00, 0xF7
};
typedef enum
{
MIDI_RESET_NONE,
@ -130,16 +118,16 @@ public:
MidiEvent(unsigned int time, midi_event_type_t type) :
mTime(time), mType(type)
{ }
MidiEvent(const MidiEvent &other) :
mTime(other.mTime), mType(other.mType)
{ }
virtual ~MidiEvent() { }
unsigned int getMidiClockTime() const { return mTime; }
virtual midi_event_type_t getEventType() const { return mType; }
private:
unsigned int mTime;
midi_event_type_t mType;
@ -158,13 +146,13 @@ public:
memcpy(mData, data, mLength);
}
}
virtual ~MidiMetaEvent()
{
if (mData)
delete mData;
}
virtual size_t getDataLength() const { return mLength; }
virtual const byte* getData() const { return mData; }
virtual midi_meta_event_type_t getMetaType() const { return mMetaType; }
@ -188,13 +176,13 @@ public:
memcpy(mData, data, mLength);
}
}
virtual ~MidiSysexEvent()
{
if (mData)
delete mData;
}
virtual size_t getDataLength() const { return mLength; }
virtual const byte* getData() const { return mData; }
@ -211,13 +199,13 @@ public:
byte param1, byte param2 = 0) :
MidiEvent(time, type), mChannel(channel), mParam1(param1), mParam2(param2)
{ }
virtual ~MidiChannelEvent() {}
byte getChannel() const { return mChannel; }
byte getParam1() const { return mParam1; }
byte getParam2() const { return mParam2; }
private:
byte mChannel;
byte mParam1;
@ -233,11 +221,11 @@ public:
MidiChannelEvent(time, MIDI_EVENT_CONTROLLER, channel, param1, 0),
mControllerType(controllertype)
{ }
virtual ~MidiControllerEvent() {}
midi_controller_t getControllerType() const { return mControllerType; }
private:
midi_controller_t mControllerType;
};
@ -248,12 +236,12 @@ class MidiSong
public:
MidiSong(byte* data, size_t length);
~MidiSong();
unsigned short getTimeDivision() { return mTimeDivision; }
typedef std::list<MidiEvent*>::iterator iterator;
typedef std::list<MidiEvent*>::const_iterator const_iterator;
// Allow iteration through a song's events
iterator begin() { return mEvents.begin(); }
const_iterator begin() const { return mEvents.begin(); }
@ -263,7 +251,7 @@ public:
private:
std::list<MidiEvent*> mEvents;
unsigned short mTimeDivision;
void _ParseSong(MEMFILE *mf);
};

View file

@ -24,7 +24,7 @@
#include "odamex.h"
#include "win32inc.h"
#if defined(_WIN32) && !defined(_XBOX)
#if defined(_WIN32)
#include <mmsystem.h>
#endif
@ -46,7 +46,7 @@ MusicSystem* musicsystem = NULL;
MusicSystemType current_musicsystem_type = MS_NONE;
void S_StopMusic();
void S_ChangeMusic (std::string musicname, bool looping);
void S_ChangeMusic (std::string musicname, bool looping, int order = 0);
EXTERN_CVAR (snd_musicvolume)
EXTERN_CVAR (snd_musicsystem)
@ -142,7 +142,7 @@ bool S_MusicIsWave(byte* data, size_t length)
//
void I_ResetMidiVolume()
{
#if defined(_WIN32) && !defined(_XBOX)
#if defined(_WIN32)
SDL_LockAudio();
for (UINT device = MIDI_MAPPER; device != midiOutGetNumDevs(); device++)
@ -288,7 +288,7 @@ static MusicSystemType I_SelectMusicSystem(byte *data, size_t length)
return MS_SDLMIXER;
}
void I_PlaySong(const OByteSpan data, const bool loop)
void I_PlaySong(const OByteSpan data, const bool loop, const int order)
{
if (!musicsystem)
return;
@ -304,7 +304,7 @@ void I_PlaySong(const OByteSpan data, const bool loop)
I_InitMusic(newtype);
}
musicsystem->startSong(data.data(), data.size(), loop);
musicsystem->startSong(data.data(), data.size(), loop, order);
// Hack for problems with Windows Vista/7 & SDL_Mixer
// See comment for I_ResetMidiVolume().

View file

@ -1,4 +1,4 @@
// Emacs style mode select -*- C++ -*-
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id$
@ -68,7 +68,7 @@ void I_ResumeSong();
// plays a song, and when the song is done,
// starts playing it again in an endless loop.
// Horrible thing to do, considering.
void I_PlaySong(const OByteSpan data, const bool loop);
void I_PlaySong(const OByteSpan data, const bool loop, const int order);
// Stops a song over 3 seconds.
void I_StopSong();
void I_UpdateMusic();

View file

@ -74,7 +74,7 @@ static double I_CalculateMsPerMidiClock(int timeDivision, double tempo = 120.0)
//
// ============================================================================
void MusicSystem::startSong(byte* data, size_t length, bool loop)
void MusicSystem::startSong(byte* data, size_t length, bool loop, int order)
{
m_isPlaying = true;
m_isPaused = false;
@ -139,15 +139,15 @@ static MidiSong* I_RegisterMidiSong(byte* data, size_t length)
}
else
{
Printf(PRINT_WARNING, "I_RegisterMidiSong: MUS is not valid\n");
PrintFmt(PRINT_WARNING, "I_RegisterMidiSong: MUS is not valid\n");
regdata = NULL;
reglength = 0;
}
}
else if (!S_MusicIsMidi(data, length))
{
Printf(PRINT_WARNING, "I_RegisterMidiSong: Only midi music formats are supported "
"with the selected music system.\n");
PrintFmt(PRINT_WARNING, "I_RegisterMidiSong: Only midi music formats are supported "
"with the selected music system.\n");
return NULL;
}
@ -214,7 +214,7 @@ void MidiMusicSystem::_DisableFallback()
m_useFallback = false;
}
void MidiMusicSystem::startSong(byte* data, size_t length, bool loop)
void MidiMusicSystem::startSong(byte* data, size_t length, bool loop, int order)
{
if (!isInitialized())
return;
@ -239,7 +239,7 @@ void MidiMusicSystem::startSong(byte* data, size_t length, bool loop)
m_prevClockTime = 0;
m_lastEventTime = I_MSTime();
MusicSystem::startSong(data, length, loop);
MusicSystem::startSong(data, length, loop, order);
}
void MidiMusicSystem::stopSong()

View file

@ -34,7 +34,7 @@ class MusicSystem
MusicSystem() { }
virtual ~MusicSystem() { }
virtual void startSong(byte* data, size_t length, bool loop);
virtual void startSong(byte* data, size_t length, bool loop, int order);
virtual void stopSong();
virtual void pauseSong();
virtual void resumeSong();
@ -74,10 +74,10 @@ class SilentMusicSystem : public MusicSystem
public:
SilentMusicSystem()
{
Printf(PRINT_WARNING, "I_InitMusic: Music playback disabled.\n");
PrintFmt(PRINT_WARNING, "I_InitMusic: Music playback disabled.\n");
}
void startSong(byte* data, size_t length, bool loop) override { }
void startSong(byte* data, size_t length, bool loop, int order) override { }
void stopSong() override { }
void pauseSong() override { }
void resumeSong() override { }
@ -109,7 +109,7 @@ class MidiMusicSystem : public MusicSystem
MidiMusicSystem();
~MidiMusicSystem() override;
void startSong(byte* data, size_t length, bool loop) override;
void startSong(byte* data, size_t length, bool loop, int order) override;
void stopSong() override;
void pauseSong() override;
void resumeSong() override;

View file

@ -76,7 +76,7 @@ AdlMidiMusicSystem::AdlMidiMusicSystem() : m_mutex()
return;
}
else
PrintFmt("I_InitMusic: Music playback enabled using libADLMIDI.\n");
PrintFmt(PRINT_FILTERHIGH, "I_InitMusic: Music playback enabled using libADLMIDI.\n");
m_isInitialized = true;
@ -127,7 +127,7 @@ static void adlmidi_music_hook (void *data, byte *stream, int len)
}
void AdlMidiMusicSystem::startSong(byte* data, size_t length, bool loop)
void AdlMidiMusicSystem::startSong(byte* data, size_t length, bool loop, int order)
{
if (!isInitialized())
return;
@ -145,7 +145,7 @@ void AdlMidiMusicSystem::startSong(byte* data, size_t length, bool loop)
adl_setLoopEnabled(m_midiPlayer, loop);
_UpdateMidiHook();
MusicSystem::startSong(data, length, loop);
MusicSystem::startSong(data, length, loop, order);
}
//

View file

@ -44,7 +44,7 @@ class AdlMidiMusicSystem : public MusicSystem
AdlMidiMusicSystem();
~AdlMidiMusicSystem() override;
void startSong(byte* data, size_t length, bool loop) override;
void startSong(byte* data, size_t length, bool loop, int order) override;
void stopSong() override;
void pauseSong() override;
void resumeSong() override;

View file

@ -95,19 +95,19 @@ AuMusicSystem::AuMusicSystem() : m_isInitialized(false)
if (AUGraphConnectNodeInput(m_graph, m_synth, 0, m_output, 0) != noErr)
{
Printf(PRINT_HIGH, "I_InitMusic: AUGraphConnectNodeInput failed\n");
PrintFmt(PRINT_HIGH, "I_InitMusic: AUGraphConnectNodeInput failed\n");
return;
}
if (AUGraphOpen(m_graph) != noErr)
{
Printf(PRINT_HIGH, "I_InitMusic: AUGraphOpen failed\n");
PrintFmt(PRINT_HIGH, "I_InitMusic: AUGraphOpen failed\n");
return;
}
if (AUGraphInitialize(m_graph) != noErr)
{
Printf(PRINT_HIGH, "I_InitMusic: AUGraphInitialize failed\n");
PrintFmt(PRINT_HIGH, "I_InitMusic: AUGraphInitialize failed\n");
return;
}
@ -118,18 +118,18 @@ AuMusicSystem::AuMusicSystem() : m_isInitialized(false)
if (AUGraphNodeInfo(m_graph, m_output, NULL, &m_unit) != noErr)
#endif
{
Printf(PRINT_HIGH, "I_InitMusic: AUGraphGetNodeInfo failed\n");
PrintFmt(PRINT_HIGH, "I_InitMusic: AUGraphGetNodeInfo failed\n");
return;
}
if (NewMusicPlayer(&m_player) != noErr)
{
Printf(PRINT_HIGH,
PrintFmt(PRINT_HIGH,
"I_InitMusic: Music player creation failed using AudioToolbox\n");
return;
}
Printf(PRINT_HIGH, "I_InitMusic: Music playback enabled using AudioToolbox\n");
PrintFmt(PRINT_FILTERHIGH, "I_InitMusic: Music playback enabled using AudioToolbox\n");
m_isInitialized = true;
return;
}
@ -143,7 +143,7 @@ AuMusicSystem::~AuMusicSystem()
AUGraphClose(m_graph);
}
void AuMusicSystem::startSong(byte* data, size_t length, bool loop)
void AuMusicSystem::startSong(byte* data, size_t length, bool loop, int order)
{
if (!isInitialized())
return;
@ -157,26 +157,26 @@ void AuMusicSystem::startSong(byte* data, size_t length, bool loop)
if (MusicSequenceSetAUGraph(m_sequence, m_graph) != noErr)
{
Printf(PRINT_HIGH, "I_PlaySong: MusicSequenceSetAUGraph failed\n");
PrintFmt(PRINT_HIGH, "I_PlaySong: MusicSequenceSetAUGraph failed\n");
return;
}
if (MusicPlayerSetSequence(m_player, m_sequence) != noErr)
{
Printf(PRINT_HIGH, "I_PlaySong: MusicPlayerSetSequence failed\n");
PrintFmt(PRINT_HIGH, "I_PlaySong: MusicPlayerSetSequence failed\n");
return;
}
if (MusicPlayerPreroll(m_player) != noErr)
{
Printf(PRINT_HIGH, "I_PlaySong: MusicPlayerPreroll failed\n");
PrintFmt(PRINT_HIGH, "I_PlaySong: MusicPlayerPreroll failed\n");
return;
}
UInt32 outNumberOfTracks = 0;
if (MusicSequenceGetTrackCount(m_sequence, &outNumberOfTracks) != noErr)
{
Printf(PRINT_HIGH, "I_PlaySong: MusicSequenceGetTrackCount failed\n");
PrintFmt(PRINT_HIGH, "I_PlaySong: MusicSequenceGetTrackCount failed\n");
return;
}
@ -189,14 +189,14 @@ void AuMusicSystem::startSong(byte* data, size_t length, bool loop)
if (MusicSequenceGetIndTrack(m_sequence, i, &track) != noErr)
{
Printf(PRINT_HIGH, "I_PlaySong: MusicSequenceGetIndTrack failed\n");
PrintFmt(PRINT_HIGH, "I_PlaySong: MusicSequenceGetIndTrack failed\n");
return;
}
if (MusicTrackGetProperty(track, kSequenceTrackProperty_TrackLength, &time,
&size) != noErr)
{
Printf(PRINT_HIGH, "I_PlaySong: MusicTrackGetProperty failed\n");
PrintFmt(PRINT_HIGH, "I_PlaySong: MusicTrackGetProperty failed\n");
return;
}
@ -220,7 +220,7 @@ void AuMusicSystem::startSong(byte* data, size_t length, bool loop)
if (MusicSequenceGetIndTrack(m_sequence, i, &track) != noErr)
{
Printf(PRINT_HIGH, "I_PlaySong: MusicSequenceGetIndTrack failed\n");
PrintFmt(PRINT_HIGH, "I_PlaySong: MusicSequenceGetIndTrack failed\n");
return;
}
@ -230,18 +230,18 @@ void AuMusicSystem::startSong(byte* data, size_t length, bool loop)
if (MusicTrackSetProperty(track, kSequenceTrackProperty_LoopInfo, &LoopInfo,
sizeof(LoopInfo)) != noErr)
{
Printf(PRINT_HIGH, "I_PlaySong: MusicTrackSetProperty failed\n");
PrintFmt(PRINT_HIGH, "I_PlaySong: MusicTrackSetProperty failed\n");
return;
}
}
if (MusicPlayerStart(m_player) != noErr)
{
Printf(PRINT_HIGH, "I_PlaySong: MusicPlayerStart failed\n");
PrintFmt(PRINT_HIGH, "I_PlaySong: MusicPlayerStart failed\n");
return;
}
MusicSystem::startSong(data, length, loop);
MusicSystem::startSong(data, length, loop, order);
}
//
@ -294,7 +294,7 @@ void AuMusicSystem::setVolume(float volume)
if (AudioUnitSetParameter(m_unit, kAudioUnitParameterUnit_LinearGain,
kAudioUnitScope_Output, 0, getVolume(), 0) != noErr)
{
Printf(PRINT_HIGH, "I_InitMusic: AudioUnitSetParameter failed\n");
PrintFmt(PRINT_HIGH, "I_InitMusic: AudioUnitSetParameter failed\n");
return;
}
}
@ -337,20 +337,20 @@ void AuMusicSystem::_RegisterSong(byte* data, size_t length)
}
else
{
Printf(PRINT_HIGH, "MUS is not valid\n");
PrintFmt(PRINT_HIGH, "MUS is not valid\n");
regdata = NULL;
reglength = 0;
}
}
else if (!S_MusicIsMidi(data, length))
{
Printf(PRINT_HIGH, "I_PlaySong: AudioUnit does not support this music format\n");
PrintFmt(PRINT_HIGH, "I_PlaySong: AudioUnit does not support this music format\n");
return;
}
if (NewMusicSequence(&m_sequence) != noErr)
{
Printf(PRINT_HIGH, "I_PlaySong: Unable to create AudioUnit sequence\n");
PrintFmt(PRINT_HIGH, "I_PlaySong: Unable to create AudioUnit sequence\n");
return;
}

View file

@ -43,7 +43,7 @@ class AuMusicSystem : public MusicSystem
AuMusicSystem();
~AuMusicSystem() override;
void startSong(byte* data, size_t length, bool loop) override;
void startSong(byte* data, size_t length, bool loop, int order) override;
void stopSong() override;
void pauseSong() override;
void resumeSong() override;

View file

@ -42,6 +42,18 @@ EXTERN_CVAR(snd_midisysex)
// Partially based on an implementation from prboom-plus by Nicholai Main (Natt).
// ============================================================================
static byte gm_system_on[] = {
0xF0, 0x7E, 0x7F, 0x09, 0x01, 0xF7
};
static byte gs_reset[] = {
0xF0, 0x41, 0x10, 0x42, 0x12, 0x40, 0x00, 0x7F, 0x00, 0x41, 0xF7
};
static byte xg_system_on[] = {
0xF0, 0x43, 0x10, 0x4C, 0x00, 0x00, 0x7E, 0x00, 0xF7
};
//
// I_PortMidiTime()
//
@ -62,7 +74,7 @@ PortMidiMusicSystem::PortMidiMusicSystem()
if (Pm_Initialize() != pmNoError)
{
Printf(PRINT_WARNING, "I_InitMusic: PortMidi initialization failed.\n");
PrintFmt(PRINT_WARNING, "I_InitMusic: PortMidi initialization failed.\n");
return;
}
@ -80,12 +92,12 @@ PortMidiMusicSystem::PortMidiMusicSystem()
if (!prefdevicename.empty() && iequals(prefdevicename, curdevicename))
m_outputDevice = i;
Printf(PRINT_HIGH, "%d: %s, %s\n", i, info->interf, info->name);
PrintFmt(PRINT_FILTERHIGH, "{}: {}, {}\n", i, info->interf, info->name);
}
if (m_outputDevice == pmNoDevice)
{
Printf(PRINT_WARNING, "I_InitMusic: No PortMidi output devices available.\n");
PrintFmt(PRINT_WARNING, "I_InitMusic: No PortMidi output devices available.\n");
Pm_Terminate();
return;
}
@ -93,8 +105,8 @@ PortMidiMusicSystem::PortMidiMusicSystem()
if (Pm_OpenOutput(&m_stream, m_outputDevice, NULL, output_buffer_size, I_PortMidiTime,
NULL, cLatency) != pmNoError)
{
Printf(PRINT_WARNING, "I_InitMusic: Failure opening PortMidi output device %d.\n",
m_outputDevice);
PrintFmt(PRINT_WARNING, "I_InitMusic: Failure opening PortMidi output device {}.\n",
m_outputDevice);
return;
}
@ -112,7 +124,7 @@ PortMidiMusicSystem::PortMidiMusicSystem()
// Initialize instrument fallback support
_InitFallback();
Printf(PRINT_HIGH, "I_InitMusic: Music playback enabled using PortMidi.\n");
PrintFmt(PRINT_FILTERHIGH, "I_InitMusic: Music playback enabled using PortMidi.\n");
m_isInitialized = true;
}
@ -303,11 +315,11 @@ void PortMidiMusicSystem::_ResetDevice(bool playing)
m_useResetDelay = (snd_mididelay > 0);
}
void PortMidiMusicSystem::startSong(byte *data, size_t length, bool loop)
void PortMidiMusicSystem::startSong(byte *data, size_t length, bool loop, int order)
{
m_isPlaying = false;
_ResetDevice(true);
MidiMusicSystem::startSong(data, length, loop);
MidiMusicSystem::startSong(data, length, loop, order);
m_isPlaying = true;
}

View file

@ -37,7 +37,7 @@ class PortMidiMusicSystem : public MidiMusicSystem
PortMidiMusicSystem();
~PortMidiMusicSystem() override;
void startSong(byte *data, size_t length, bool loop) override;
void startSong(byte *data, size_t length, bool loop, int order) override;
void stopSong() override;
void pauseSong() override;
void restartSong() override;

View file

@ -31,21 +31,11 @@
#include "i_music.h"
#include "mus2midi.h"
// [Russell] - define a temporary midi file, for consistency
// SDL < 1.2.7
#ifdef _XBOX
// Use the cache partition
#define TEMP_MIDI "Z:\\temp_music"
#elif MIX_MAJOR_VERSION < 1 || (MIX_MAJOR_VERSION == 1 && MIX_MINOR_VERSION < 2) || \
(MIX_MAJOR_VERSION == 1 && MIX_MINOR_VERSION == 2 && MIX_PATCHLEVEL < 7)
#define TEMP_MIDI "temp_music"
#endif
EXTERN_CVAR(snd_musicvolume)
SdlMixerMusicSystem::SdlMixerMusicSystem() : m_isInitialized(false), m_registeredSong()
{
Printf("I_InitMusic: Music playback enabled using SDL_Mixer.\n");
PrintFmt(PRINT_FILTERHIGH, "I_InitMusic: Music playback enabled using SDL_Mixer.\n");
m_isInitialized = true;
}
@ -60,7 +50,7 @@ SdlMixerMusicSystem::~SdlMixerMusicSystem()
m_isInitialized = false;
}
void SdlMixerMusicSystem::startSong(byte* data, size_t length, bool loop)
void SdlMixerMusicSystem::startSong(byte* data, size_t length, bool loop, int order)
{
if (!isInitialized())
return;
@ -77,13 +67,17 @@ void SdlMixerMusicSystem::startSong(byte* data, size_t length, bool loop)
if (Mix_PlayMusic(m_registeredSong.Track, loop ? -1 : 1) == -1)
{
Printf(PRINT_WARNING, "Mix_PlayMusic: %s\n", Mix_GetError());
PrintFmt(PRINT_WARNING, "Mix_PlayMusic: {}\n", Mix_GetError());
return;
}
#if (SDL_MIXER_MAJOR_VERSION == 2 && SDL_MIXER_MINOR_VERSION >= 6)
Mix_ModMusicJumpToOrder(order); // for musinfo
#endif
Mix_HookMusicFinished(I_ResetMidiVolume);
MusicSystem::startSong(data, length, loop);
MusicSystem::startSong(data, length, loop, order);
// [Russell] - Hack for setting the volume on windows vista, since it gets
// reset on every music change
@ -98,7 +92,7 @@ void SdlMixerMusicSystem::startSong(byte* data, size_t length, bool loop)
//
void SdlMixerMusicSystem::_StopSong()
{
if (!isInitialized() || !isPlaying())
if (!isInitialized())
return;
if (isPaused())
@ -197,7 +191,7 @@ void SdlMixerMusicSystem::_RegisterSong(byte* data, size_t length)
}
else
{
Printf(PRINT_WARNING, "MUS is not valid\n");
PrintFmt(PRINT_WARNING, "MUS is not valid\n");
}
mem_fclose(mus);
@ -209,62 +203,15 @@ void SdlMixerMusicSystem::_RegisterSong(byte* data, size_t length)
if (!m_registeredSong.Data)
{
Printf(PRINT_WARNING, "SDL_RWFromMem: %s\n", SDL_GetError());
PrintFmt(PRINT_WARNING, "SDL_RWFromMem: {}\n", SDL_GetError());
return;
}
#ifdef TEMP_MIDI
// We're using an older version of SDL and must save the midi data
// to a temporary file first
FILE* fp = fopen(TEMP_MIDI, "wb+");
if (!fp)
{
Printf(PRINT_WARNING,
"Could not open temporary music file %s, not playing track\n", TEMP_MIDI);
return;
}
// Get the size of the music data
SDL_RWseek(m_registeredSong.Data, 0, SEEK_END);
size_t reglength = SDL_RWtell(m_registeredSong.Data);
// Write the music data to the temporary file
SDL_RWseek(m_registeredSong.Data, 0, SEEK_SET);
char buf[1024];
while (reglength)
{
size_t chunksize = reglength > sizeof(buf) ? sizeof(buf) : reglength;
SDL_RWread(m_registeredSong.Data, buf, chunksize, 1);
fwrite(buf, chunksize, 1, fp);
reglength -= chunksize;
}
fclose(fp);
// Read the midi data from the temporary file
m_registeredSong.Track = Mix_LoadMUS(TEMP_MIDI);
unlink(TEMP_MIDI); // remove the temporary file
if (!m_registeredSong.Track)
{
Printf(PRINT_WARNING, "Mix_LoadMUSW: %s\n", Mix_GetError());
return;
}
#else
// We can read the midi data directly from memory
#ifdef SDL20
m_registeredSong.Track = Mix_LoadMUS_RW(m_registeredSong.Data, 0);
#elif defined SDL12
m_registeredSong.Track = Mix_LoadMUS_RW(m_registeredSong.Data);
#endif // SDL12
if (!m_registeredSong.Track)
{
Printf(PRINT_WARNING, "Mix_LoadMUS_RW: %s\n", Mix_GetError());
PrintFmt(PRINT_WARNING, "Mix_LoadMUS_RW: {}\n", Mix_GetError());
return;
}
#endif // TEMP_MIDI
}

View file

@ -37,7 +37,7 @@ class SdlMixerMusicSystem : public MusicSystem
SdlMixerMusicSystem();
~SdlMixerMusicSystem() override;
void startSong(byte* data, size_t length, bool loop) override ;
void startSong(byte* data, size_t length, bool loop, int order) override ;
void stopSong() override ;
void pauseSong() override ;
void resumeSong() override ;

View file

@ -25,7 +25,9 @@
#include <SDL.h>
#if (SDL_MAJOR_VERSION == 2)
#if (SDL_MAJOR_VERSION == 3)
#define SDL3
#elif (SDL_MAJOR_VERSION == 2)
#define SDL20
#if (SDL_MINOR_VERSION > 0 || SDL_PATCHLEVEL >= 16)
#define SDL2016

View file

@ -40,10 +40,6 @@
#include "m_misc.h"
#include "w_wad.h"
#ifdef _XBOX
#include "i_xbox.h"
#endif
#define NUM_CHANNELS 32
static int mixer_freq;
@ -230,8 +226,8 @@ static Uint8 *perform_sdlmix_conv(Uint8 *data, Uint32 size, Uint32 *newsize)
if (!mem_op)
{
Printf(PRINT_HIGH,
"perform_sdlmix_conv - SDL_RWFromMem: %s\n", SDL_GetError());
PrintFmt(PRINT_HIGH,
"perform_sdlmix_conv - SDL_RWFromMem: {}\n", SDL_GetError());
return NULL;
}
@ -240,8 +236,8 @@ static Uint8 *perform_sdlmix_conv(Uint8 *data, Uint32 size, Uint32 *newsize)
if (!chunk)
{
Printf(PRINT_HIGH,
"perform_sdlmix_conv - Mix_LoadWAV_RW: %s\n", Mix_GetError());
PrintFmt(PRINT_HIGH,
"perform_sdlmix_conv - Mix_LoadWAV_RW: {}\n", Mix_GetError());
return NULL;
}
@ -483,28 +479,21 @@ void I_InitSound()
if (I_IsHeadless() || Args.CheckParm("-nosound"))
return;
#if defined(SDL12)
const char *driver = getenv("SDL_AUDIODRIVER");
if(!driver)
driver = "default";
Printf(PRINT_HIGH, "I_InitSound: Initializing SDL's sound subsystem (%s)\n", driver);
#elif defined(SDL20)
Printf("I_InitSound: Initializing SDL's sound subsystem\n");
#if defined(SDL20)
PrintFmt("I_InitSound: Initializing SDL's sound subsystem\n");
#endif
if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
{
Printf(PRINT_ERROR,
"I_InitSound: Unable to set up sound: %s\n",
SDL_GetError());
PrintFmt(PRINT_ERROR,
"I_InitSound: Unable to set up sound: {}\n",
SDL_GetError());
return;
}
#if defined(SDL20)
Printf("I_InitSound: Using SDL's audio driver (%s)\n", SDL_GetCurrentAudioDriver());
PrintFmt("I_InitSound: Using SDL's audio driver ({})\n", SDL_GetCurrentAudioDriver());
#endif
const SDL_version *ver = Mix_Linked_Version();
@ -512,7 +501,7 @@ void I_InitSound()
if(ver->major != MIX_MAJOR_VERSION
|| ver->minor != MIX_MINOR_VERSION)
{
Printf(PRINT_ERROR, "I_InitSound: SDL_mixer version conflict (%d.%d.%d vs %d.%d.%d dll)\n",
PrintFmt(PRINT_ERROR, "I_InitSound: SDL_mixer version conflict ({}.{}.{} vs {}.{}.{} dll)\n",
MIX_MAJOR_VERSION, MIX_MINOR_VERSION, MIX_PATCHLEVEL,
ver->major, ver->minor, ver->patch);
return;
@ -520,12 +509,12 @@ void I_InitSound()
if(ver->patch != MIX_PATCHLEVEL)
{
Printf(PRINT_WARNING, "I_InitSound: SDL_mixer version warning (%d.%d.%d vs %d.%d.%d dll)\n",
PrintFmt(PRINT_WARNING, "I_InitSound: SDL_mixer version warning ({}.{}.{} vs {}.{}.{} dll)\n",
MIX_MAJOR_VERSION, MIX_MINOR_VERSION, MIX_PATCHLEVEL,
ver->major, ver->minor, ver->patch);
}
Printf(PRINT_HIGH, "I_InitSound: Initializing SDL_mixer\n");
PrintFmt(PRINT_HIGH, "I_InitSound: Initializing SDL_mixer\n");
#ifdef SDL20
// Apparently, when Mix_OpenAudio requests a certain number of channels
@ -539,23 +528,23 @@ void I_InitSound()
if (Mix_OpenAudio((int)snd_samplerate, AUDIO_S16SYS, 2, 1024) < 0)
#endif
{
Printf(PRINT_ERROR,
"I_InitSound: Error initializing SDL_mixer: %s\n",
Mix_GetError());
PrintFmt(PRINT_ERROR,
"I_InitSound: Error initializing SDL_mixer: {}\n",
Mix_GetError());
return;
}
if(!Mix_QuerySpec(&mixer_freq, &mixer_format, &mixer_channels))
{
Printf(PRINT_ERROR,
"I_InitSound: Error initializing SDL_mixer: %s\n",
Mix_GetError());
PrintFmt(PRINT_ERROR,
"I_InitSound: Error initializing SDL_mixer: {}\n",
Mix_GetError());
return;
}
Printf("I_InitSound: Using %d channels (freq:%d, fmt:%d, chan:%d)\n",
Mix_AllocateChannels(NUM_CHANNELS),
mixer_freq, mixer_format, mixer_channels);
PrintFmt("I_InitSound: Using {} channels (freq:{}, fmt:{}, chan:{})\n",
Mix_AllocateChannels(NUM_CHANNELS),
mixer_freq, mixer_format, mixer_channels);
atterm(I_ShutdownSound);
@ -563,7 +552,7 @@ void I_InitSound()
SDL_PauseAudio(0);
Printf("I_InitSound: sound module ready\n");
PrintFmt("I_InitSound: sound module ready\n");
I_InitMusic();

View file

@ -41,27 +41,22 @@
#include "win32inc.h"
#ifdef _WIN32
#include <direct.h>
#include <io.h>
#include <process.h>
#ifdef _XBOX
#include <xtl.h>
#else
#include <shlwapi.h>
#include <winsock2.h>
#include <mmsystem.h>
#include <shlobj.h>
#endif // !_XBOX
#include <direct.h>
#include <io.h>
#include <process.h>
#include <shlwapi.h>
#include <winsock2.h>
#include <mmsystem.h>
#include <shlobj.h>
#endif // WIN32
#ifdef UNIX
// for getuid and geteuid
#include <unistd.h>
#include <sys/types.h>
#include <limits.h>
#include <time.h>
#include <pwd.h>
#include <unistd.h>
#include <sys/types.h>
#include <limits.h>
#include <time.h>
#include <pwd.h>
#endif
#include <sstream>
@ -93,14 +88,6 @@
#include "m_fileio.h"
#include "txt_main.h"
#ifdef _XBOX
#include "i_xbox.h"
#endif
#ifdef GEKKO
#include "i_wii.h"
#endif
#ifndef GCONSOLE // I will add this back later -- Hyper_Eye
// For libtextscreen to link properly
extern "C"
@ -109,7 +96,7 @@
}
#define ENDOOM_W 80
#define ENDOOM_H 25
#endif // _XBOX
#endif // GCONSOLE
EXTERN_CVAR (r_loadicon)
EXTERN_CVAR (r_showendoom)
@ -173,12 +160,12 @@ dtime_t I_GetTime()
mach_port_deallocate(mach_task_self(), cclock);
return mts.tv_sec * 1000LL * 1000LL * 1000LL + mts.tv_nsec;
#elif defined UNIX && !defined GEKKO
#elif defined UNIX
timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec * 1000LL * 1000LL * 1000LL + ts.tv_nsec;
#elif defined WIN32 && !defined _XBOX
#elif defined WIN32
static bool initialized = false;
static LARGE_INTEGER initial_count;
static double nanoseconds_per_count;
@ -262,7 +249,7 @@ void I_Sleep(dtime_t sleep_time)
#if defined UNIX
usleep(sleep_time / 1000LL);
#elif defined(WIN32) && !defined(_XBOX)
#elif defined(WIN32)
Sleep(sleep_time / 1000000LL);
#else
@ -295,7 +282,7 @@ void I_WaitVBL(int count)
//
// SubsetLanguageIDs
//
#if defined _WIN32 && !defined _XBOX
#if defined _WIN32
static void SubsetLanguageIDs (LCID id, LCTYPE type, int idx)
{
char buf[8];
@ -324,16 +311,35 @@ void SetLanguageIDs()
if (strcmp(langid, "auto") == 0)
{
#if defined _WIN32 && !defined _XBOX
#if defined _WIN32
memset(LanguageIDs, 0, sizeof(LanguageIDs));
SubsetLanguageIDs(LOCALE_USER_DEFAULT, LOCALE_ILANGUAGE, 0);
SubsetLanguageIDs(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTLANGUAGE, 1);
SubsetLanguageIDs(LOCALE_SYSTEM_DEFAULT, LOCALE_ILANGUAGE, 2);
SubsetLanguageIDs(LOCALE_SYSTEM_DEFAULT, LOCALE_IDEFAULTLANGUAGE, 3);
#elif SDL_VERSION_ATLEAST(2, 0, 14)
SDL_Locale* locales = SDL_GetPreferredLocales();
size_t i;
for (i = 0; i < ARRAY_LENGTH(LanguageIDs) && locales && locales->language; i++)
{
char slang[4] = {'\0', '\0', '\0', '\0'};
strncpy(slang, locales->language, ARRAY_LENGTH(slang) - 1);
const uint32_t lang = MAKE_ID(slang[0], slang[1], slang[2], slang[3]);
LanguageIDs[i] = lang;
}
if (i < ARRAY_LENGTH(LanguageIDs))
{
// Fill the rest with the last valid entry
for (; i < ARRAY_LENGTH(LanguageIDs); i++)
LanguageIDs[i] = LanguageIDs[i - 1];
}
#else
// Default to US English on non-windows systems
// FIXME: Use SDL Locale support if available.
langid = "enu";
static constexpr uint32_t lang = MAKE_ID('e', 'n', 'u', '\0');
LanguageIDs[0] = lang;
LanguageIDs[1] = lang;
LanguageIDs[2] = lang;
LanguageIDs[3] = lang;
#endif
}
else
@ -465,7 +471,7 @@ void STACK_ARGS call_terms (void);
void I_BaseWarning(const std::string& warningtext)
{
Printf(PRINT_WARNING, "\n%s\n", warningtext);
PrintFmt(PRINT_WARNING, "\n{}\n", warningtext);
}
void I_BaseError(const std::string& errortext)
@ -578,7 +584,7 @@ std::string I_GetClipboardText()
if (!dis)
{
Printf(PRINT_HIGH, "I_GetClipboardText: XOpenDisplay failed");
PrintFmt(PRINT_HIGH, "I_GetClipboardText: XOpenDisplay failed");
return "";
}
@ -594,7 +600,7 @@ std::string I_GetClipboardText()
XDestroyWindow(dis, WindowEvents);
XUnlockDisplay(dis);
XCloseDisplay(dis);
Printf(PRINT_HIGH, "I_GetClipboardText: XConvertSelection failed");
PrintFmt(PRINT_HIGH, "I_GetClipboardText: XConvertSelection failed");
return "";
}
@ -622,7 +628,7 @@ std::string I_GetClipboardText()
XDestroyWindow(dis, WindowEvents);
XUnlockDisplay(dis);
XCloseDisplay(dis);
Printf(PRINT_HIGH, "I_GetClipboardText: XGetWindowProperty failed(1)");
PrintFmt(PRINT_HIGH, "I_GetClipboardText: XGetWindowProperty failed(1)");
return "";
}
@ -642,7 +648,7 @@ std::string I_GetClipboardText()
XDestroyWindow(dis, WindowEvents);
XUnlockDisplay(dis);
XCloseDisplay(dis);
Printf(PRINT_HIGH, "I_GetClipboardText: XGetWindowProperty failed(2)");
PrintFmt(PRINT_HIGH, "I_GetClipboardText: XGetWindowProperty failed(2)");
return "";
}
@ -657,7 +663,7 @@ std::string I_GetClipboardText()
return ret;
#endif
#if defined _WIN32 && !defined _XBOX
#if defined _WIN32
std::string ret;
if(!IsClipboardFormatAvailable(CF_TEXT))
@ -706,7 +712,7 @@ std::string I_GetClipboardText()
if (err)
{
Printf(PRINT_HIGH, "GetCurrentScrap error: %d", err);
PrintFmt(PRINT_HIGH, "GetCurrentScrap error: {}", err);
return "";
}
@ -714,7 +720,7 @@ std::string I_GetClipboardText()
if (err)
{
Printf(PRINT_HIGH, "GetScrapFlavorSize error: %d", err);
PrintFmt(PRINT_HIGH, "GetScrapFlavorSize error: {}", err);
return "";
}
@ -725,7 +731,7 @@ std::string I_GetClipboardText()
if(err)
{
Printf(PRINT_HIGH, "GetScrapFlavorData error: %d", err);
PrintFmt(PRINT_HIGH, "GetScrapFlavorData error: {}", err);
delete[] data;
return "";
@ -744,7 +750,7 @@ std::string I_GetClipboardText()
if (NULL == textp)
{
Printf(PRINT_HIGH, "SDL_GetClipboardText error: %s", SDL_GetError());
PrintFmt(PRINT_HIGH, "SDL_GetClipboardText error: {}", SDL_GetError());
return "";
}
@ -921,7 +927,7 @@ void I_ErrorMessageBox(const char* message)
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, ODAMEX_ERROR_TITLE, message, NULL);
}
#elif defined(WIN32) && !defined(_XBOX)
#elif defined(WIN32)
void I_ErrorMessageBox(const char* message)
{

View file

@ -89,21 +89,21 @@ void I_BaseError(const std::string& errortext);
[[noreturn]] void I_BaseFatalError(const std::string& errortext);
template <typename... ARGS>
void I_Warning(const fmt::string_view format, const ARGS&... args)
void I_Warning(fmt::format_string<ARGS...> format, ARGS&&... args)
{
I_BaseWarning(fmt::format(format, args...));
I_BaseWarning(fmt::format(format, std::forward<ARGS>(args)...));
}
template <typename... ARGS>
void I_Error(const fmt::string_view format, const ARGS&... args)
void I_Error(fmt::format_string<ARGS...> format, ARGS&&... args)
{
I_BaseError(fmt::format(format, args...));
I_BaseError(fmt::format(format, std::forward<ARGS>(args)...));
}
template <typename... ARGS>
[[noreturn]] void I_FatalError(const fmt::string_view format, const ARGS&... args)
[[noreturn]] void I_FatalError(fmt::format_string<ARGS...> format, ARGS&&... args)
{
I_BaseFatalError(fmt::format(format, args...));
I_BaseFatalError(fmt::format(format, std::forward<ARGS>(args)...));
}
void addterm (void (STACK_ARGS *func)(void), const char *name);

View file

@ -33,9 +33,7 @@
#include "i_video.h"
#include "v_video.h"
#if defined(SDL12)
#include "i_video_sdl12.h"
#elif defined(SDL20)
#if defined(SDL20)
#include "i_video_sdl20.h"
#else
#error "no video subsystem selected"
@ -51,7 +49,7 @@
// [Russell] - Just for windows, display the icon in the system menu and
// alt-tab display
#if defined(_WIN32) && !defined(_XBOX)
#if defined(_WIN32)
#include "win32inc.h"
#include "SDL_syswm.h"
#include "resource.h"
@ -931,9 +929,7 @@ void I_InitHardware()
}
else
{
#if defined(SDL12)
video_subsystem = new ISDL12VideoSubsystem();
#elif defined(SDL20)
#if defined(SDL20)
video_subsystem = new ISDL20VideoSubsystem();
#endif
assert(video_subsystem != NULL);

View file

@ -1,837 +0,0 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id$
//
// Copyright (C) 2006-2025 by The Odamex Team.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// SDL 1.2 implementation of the IVideo class.
//
//-----------------------------------------------------------------------------
#include "odamex.h"
#include "i_video_sdl12.h"
#include "i_sdl.h"
#include <stdlib.h>
#include <cassert>
#include <algorithm>
#include <functional>
#include "i_video.h"
#include "v_video.h"
#include "v_palette.h"
#include "i_system.h"
#include "i_input.h"
#include "i_icon.h"
#include "c_dispatch.h"
// [Russell] - Just for windows, display the icon in the system menu and alt-tab display
#include "win32inc.h"
#if defined(_WIN32) && !defined(_XBOX)
#include <SDL_syswm.h>
#include "resource.h"
#endif // WIN32
#ifdef _XBOX
#include "i_xbox.h"
#endif
EXTERN_CVAR (vid_fullscreen)
EXTERN_CVAR (vid_widescreen)
EXTERN_CVAR (vid_pillarbox)
// ****************************************************************************
#ifdef SDL12
// ============================================================================
//
// ISDL12VideoCapabilities class implementation
//
// ============================================================================
//
// I_AddSDL12VideoModes
//
// Queries SDL to find the supported video modes at the given bit depth
// and then adds them to modelist.
//
static void I_AddSDL12VideoModes(IVideoModeList* modelist, int bpp)
{
SDL_PixelFormat format;
memset(&format, 0, sizeof(format));
format.BitsPerPixel = bpp;
SDL_Rect** sdlmodes = SDL_ListModes(&format, SDL_ANYFORMAT | SDL_FULLSCREEN | SDL_SWSURFACE);
if (sdlmodes)
{
if (sdlmodes == (SDL_Rect**)-1)
{
// SDL 1.2 documentation indicates the following
// "-1: Any dimension is okay for the given format"
// Shouldn't happen with SDL_FULLSCREEN flag though
I_FatalError("SDL_ListModes returned -1. Internal error.\n");
return;
}
// add the video modes reported by SDL
while (*sdlmodes)
{
int width = (*sdlmodes)->w, height = (*sdlmodes)->h;
if (width > 0 && width <= MAXWIDTH && height > 0 && height <= MAXHEIGHT)
{
// add this video mode to the list (both fullscreen & windowed)
modelist->push_back(IVideoMode(width, height, bpp, WINDOW_Windowed));
modelist->push_back(IVideoMode(width, height, bpp, WINDOW_Fullscreen));
}
++sdlmodes;
}
}
}
#ifdef _WIN32
static bool Is8bppFullScreen(const IVideoMode& mode)
{ return mode.bpp == 8 && mode.isFullScreen(); }
#endif
//
// ISDL12VideoCapabilities::ISDL12VideoCapabilities
//
// Discovers the native desktop resolution and queries SDL for a list of
// supported fullscreen video modes.
//
// NOTE: discovering the native desktop resolution only works if this is called
// prior to the first SDL_SetVideoMode call!
//
// NOTE: SDL has palette issues in 8bpp fullscreen mode on Windows platforms. As
// a workaround, we force a 32bpp resolution in this case by removing all
// fullscreen 8bpp video modes on Windows platforms.
//
ISDL12VideoCapabilities::ISDL12VideoCapabilities() :
IVideoCapabilities(),
mNativeMode(SDL_GetVideoInfo()->current_w, SDL_GetVideoInfo()->current_h,
SDL_GetVideoInfo()->vfmt->BitsPerPixel, WINDOW_Fullscreen)
{
I_AddSDL12VideoModes(&mModeList, 8);
I_AddSDL12VideoModes(&mModeList, 32);
// always add the following windowed modes (if windowed modes are supported)
if (supportsWindowed())
{
if (supports8bpp())
{
mModeList.push_back(IVideoMode(320, 200, 8, WINDOW_Windowed));
mModeList.push_back(IVideoMode(320, 240, 8, WINDOW_Windowed));
mModeList.push_back(IVideoMode(640, 400, 8, WINDOW_Windowed));
mModeList.push_back(IVideoMode(640, 480, 8, WINDOW_Windowed));
}
if (supports32bpp())
{
mModeList.push_back(IVideoMode(320, 200, 32, WINDOW_Windowed));
mModeList.push_back(IVideoMode(320, 240, 32, WINDOW_Windowed));
mModeList.push_back(IVideoMode(640, 400, 32, WINDOW_Windowed));
mModeList.push_back(IVideoMode(640, 480, 32, WINDOW_Windowed));
}
}
// reverse sort the modes
std::sort(mModeList.begin(), mModeList.end(), std::greater<IVideoMode>());
// get rid of any duplicates (SDL sometimes reports duplicates)
mModeList.erase(std::unique(mModeList.begin(), mModeList.end()), mModeList.end());
#ifdef _WIN32
// fullscreen directx requires a 32-bit mode to fix broken palette
// [Russell] - Use for gdi as well, fixes d2 map02 water
// [SL] remove all fullscreen 8bpp modes
mModeList.erase(std::remove_if(mModeList.begin(), mModeList.end(), Is8bppFullScreen), mModeList.end());
#endif
assert(supportsWindowed() || supportsFullScreen());
assert(supports8bpp() || supports32bpp());
}
// ****************************************************************************
// ============================================================================
//
// ISDL12DirectWindowSurfaceManager implementation
//
// Helper class for IWindow to encapsulate the creation of a IWindowSurface
// primary surface and to assist in using it to refresh the window.
//
// ============================================================================
//
// ISDL12DirectWindowSurfaceManager::ISDL12DirectWindowSurfaceManager
//
ISDL12DirectWindowSurfaceManager::ISDL12DirectWindowSurfaceManager(
uint16_t width, uint16_t height, const PixelFormat* format)
{
SDL_Surface* sdl_surface = SDL_GetVideoSurface();
assert(sdl_surface != NULL);
mSurface = new IWindowSurface(width, height, format, sdl_surface->pixels, sdl_surface->pitch);
assert(mSurface != NULL);
}
//
// ISDL12DirectWindowSurfaceManager::~ISDL12DirectWindowSurfaceManager
//
ISDL12DirectWindowSurfaceManager::~ISDL12DirectWindowSurfaceManager()
{
delete mSurface;
}
//
// ISDL12DirectWindowSurfaceManager::lockSurface
//
void ISDL12DirectWindowSurfaceManager::lockSurface()
{
SDL_Surface* sdl_surface = SDL_GetVideoSurface();
assert(sdl_surface != NULL);
if (SDL_MUSTLOCK(sdl_surface))
SDL_LockSurface(sdl_surface);
}
//
// ISDL12DirectWindowSurfaceManager::unlockSurface
//
void ISDL12DirectWindowSurfaceManager::unlockSurface()
{
SDL_Surface* sdl_surface = SDL_GetVideoSurface();
assert(sdl_surface != NULL);
if (SDL_MUSTLOCK(sdl_surface))
SDL_UnlockSurface(sdl_surface);
}
//
// ISDL12DirectWindowSurfaceManager::startRefresh
//
void ISDL12DirectWindowSurfaceManager::startRefresh()
{ }
//
// ISDL12DirectWindowSurfaceManager::finishRefresh
//
void ISDL12DirectWindowSurfaceManager::finishRefresh()
{
SDL_Surface* sdl_surface = SDL_GetVideoSurface();
assert(sdl_surface != NULL);
SDL_Flip(sdl_surface);
}
// ============================================================================
//
// ISDL12SoftwareWindowSurfaceManager implementation
//
// Helper class for IWindow to encapsulate the creation of a IWindowSurface
// primary surface and to assist in using it to refresh the window.
//
//
// ============================================================================
//
// ISDL12SoftwareWindowSurfaceManager::ISDL12SoftwareWindowSurfaceManager
//
ISDL12SoftwareWindowSurfaceManager::ISDL12SoftwareWindowSurfaceManager(
uint16_t width, uint16_t height, const PixelFormat* format)
{
mSurface = new IWindowSurface(width, height, format);
assert(mSurface != NULL);
uint32_t rmask = uint32_t(format->getRMax()) << format->getRShift();
uint32_t gmask = uint32_t(format->getGMax()) << format->getGShift();
uint32_t bmask = uint32_t(format->getBMax()) << format->getBShift();
mSDLSoftwareSurface = SDL_CreateRGBSurfaceFrom(
mSurface->getBuffer(),
mSurface->getWidth(), mSurface->getHeight(),
mSurface->getBitsPerPixel(),
mSurface->getPitch(),
rmask, gmask, bmask, 0);
assert(mSDLSoftwareSurface != NULL);
SDL_Surface* sdl_surface = SDL_GetVideoSurface();
assert(mSDLSoftwareSurface->format->Rmask == sdl_surface->format->Rmask &&
mSDLSoftwareSurface->format->Gmask == sdl_surface->format->Gmask &&
mSDLSoftwareSurface->format->Bmask == sdl_surface->format->Bmask);
}
//
// ISDL12SoftwareWindowSurfaceManager::~ISDL12SoftwareWindowSurfaceManager
//
ISDL12SoftwareWindowSurfaceManager::~ISDL12SoftwareWindowSurfaceManager()
{
if (mSDLSoftwareSurface)
SDL_FreeSurface(mSDLSoftwareSurface);
delete mSurface;
}
//
// ISDL12SoftwareWindowSurfaceManager::lockSurface
//
void ISDL12SoftwareWindowSurfaceManager::lockSurface()
{
SDL_Surface* sdl_surface = SDL_GetVideoSurface();
if (SDL_MUSTLOCK(sdl_surface))
SDL_LockSurface(sdl_surface);
if (SDL_MUSTLOCK(mSDLSoftwareSurface))
SDL_LockSurface(mSDLSoftwareSurface);
}
//
// ISDL12SoftwareWindowSurfaceManager::unlockSurface
//
void ISDL12SoftwareWindowSurfaceManager::unlockSurface()
{
SDL_Surface* sdl_surface = SDL_GetVideoSurface();
if (SDL_MUSTLOCK(sdl_surface))
SDL_UnlockSurface(sdl_surface);
if (SDL_MUSTLOCK(mSDLSoftwareSurface))
SDL_UnlockSurface(mSDLSoftwareSurface);
}
//
// ISDL12SoftwareWindowSurfaceManager::startRefresh
//
void ISDL12SoftwareWindowSurfaceManager::startRefresh()
{
}
//
// ISDL12SoftwareWindowSurfaceManager::finishRefresh
//
void ISDL12SoftwareWindowSurfaceManager::finishRefresh()
{
SDL_Surface* main_sdl_surface = SDL_GetVideoSurface();
assert(main_sdl_surface != NULL);
SDL_BlitSurface(mSDLSoftwareSurface, NULL, main_sdl_surface, NULL);
SDL_Flip(main_sdl_surface);
}
// ============================================================================
//
// ISDL12Window class implementation
//
// ============================================================================
//
// ISDL12Window::ISDL12Window (if windowed modes are supported)
//
// Constructs a new application window using SDL 1.2.
// A ISDL12WindowSurface object is instantiated for frame rendering.
//
ISDL12Window::ISDL12Window(uint16_t width, uint16_t height, uint8_t bpp, EWindowMode window_mode, bool vsync) :
IWindow(),
mSurfaceManager(NULL),
mVideoMode(0, 0, 0, WINDOW_Windowed),
mNeedPaletteRefresh(true), mBlit(true), mIgnoreResize(false), mLocks(0)
{ }
//
// ISDL12Window::~ISDL12Window
//
ISDL12Window::~ISDL12Window()
{
delete mSurfaceManager;
}
//
// ISDL12Window::lockSurface
//
// Locks the surface for direct pixel access. This must be called prior to
// accessing the primary surface's buffer.
//
void ISDL12Window::lockSurface()
{
if (++mLocks == 1)
mSurfaceManager->lockSurface();
assert(mLocks >= 1 && mLocks < 100);
}
//
// ISDL12Window::unlockSurface
//
// Unlocks the surface after direct pixel access. This must be called after
// accessing the primary surface's buffer.
//
void ISDL12Window::unlockSurface()
{
if (--mLocks == 0)
mSurfaceManager->unlockSurface();
assert(mLocks >= 0 && mLocks < 100);
}
//
// ISDL12Window::getEvents
//
// Retrieves events for the application window and processes them.
//
void ISDL12Window::getEvents()
{
// Force SDL to gather events from input devices. This is called
// implicitly from SDL_PollEvent but since we're using SDL_PeepEvents to
// process only mouse events, SDL_PumpEvents is necessary.
SDL_PumpEvents();
// Retrieve chunks of up to 1024 events from SDL
int num_events = 0;
const int max_events = 1024;
SDL_Event sdl_events[max_events];
// set mask to get all events except keyboard, mouse, and joystick events
const int event_mask = SDL_ALLEVENTS & ~SDL_KEYEVENTMASK & ~SDL_MOUSEEVENTMASK & ~SDL_JOYEVENTMASK;
while ((num_events = SDL_PeepEvents(sdl_events, max_events, SDL_GETEVENT, event_mask)))
{
for (int i = 0; i < num_events; i++)
{
const SDL_Event& sdl_ev = sdl_events[i];
if (sdl_ev.type == SDL_QUIT)
{
AddCommandString("quit");
}
else if (sdl_ev.type == SDL_VIDEORESIZE)
{
// Resizable window mode resolutions
if ((EWindowMode)vid_fullscreen.asInt() == WINDOW_Windowed && !mIgnoreResize)
{
char tmp[256];
sprintf(tmp, "vid_setmode %i %i", sdl_ev.resize.w, sdl_ev.resize.h);
AddCommandString(tmp);
}
}
else if (sdl_ev.type == SDL_ACTIVEEVENT)
{
// Debugging messages
if (sdl_ev.active.state & SDL_APPMOUSEFOCUS)
DPrintFmt("SDL_ACTIVEEVENT SDL_APPMOUSEFOCUS {}\n", sdl_ev.active.gain ? "gained" : "lost");
if (sdl_ev.active.state & SDL_APPINPUTFOCUS)
DPrintFmt("SDL_ACTIVEEVENT SDL_APPINPUTFOCUS {}\n", sdl_ev.active.gain ? "gained" : "lost");
if (sdl_ev.active.state & SDL_APPACTIVE)
DPrintFmt("SDL_ACTIVEEVENT SDL_APPACTIVE {}\n", sdl_ev.active.gain ? "gained" : "lost");
// TODO: do we need to do anything here anymore?
}
}
}
mIgnoreResize = false;
}
//
// ISDL12Window::startRefresh
//
void ISDL12Window::startRefresh()
{
getEvents();
mSurfaceManager->startRefresh();
}
//
// ISDL12Window::finishRefresh
//
void ISDL12Window::finishRefresh()
{
assert(mLocks == 0); // window surface shouldn't be locked when blitting
SDL_Surface* sdlsurface = SDL_GetVideoSurface();
if (mNeedPaletteRefresh)
{
Uint32 flags = SDL_LOGPAL | SDL_PHYSPAL;
if (sdlsurface->format->BitsPerPixel == 8)
SDL_SetPalette(sdlsurface, flags, sdlsurface->format->palette->colors, 0, 256);
// if (mSDLSoftwareSurface && mSDLSoftwareSurface->format->BitsPerPixel == 8)
// SDL_SetPalette(mSDLSoftwareSurface, flags, mSDLSoftwareSurface->format->palette->colors, 0, 256);
}
mNeedPaletteRefresh = false;
if (mBlit)
{
mSurfaceManager->finishRefresh();
}
}
//
// ISDL12Window::setWindowTitle
//
// Sets the title caption of the window.
//
void ISDL12Window::setWindowTitle(const std::string& str)
{
SDL_WM_SetCaption(str.c_str(), str.c_str());
}
//
// ISDL12Window::setWindowIcon
//
// Sets the icon for the application window, which will appear in the
// window manager's task list.
//
void ISDL12Window::setWindowIcon()
{
#if defined(_WIN32) && !defined(_XBOX)
// [SL] Use Win32-specific code to make use of multiple-icon sizes
// stored in the executable resources. SDL 1.2 only allows a fixed
// 32x32 px icon.
//
// [Russell] - Just for windows, display the icon in the system menu and
// alt-tab display
HICON hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON1));
if (hIcon)
{
SDL_SysWMinfo wminfo;
SDL_VERSION(&wminfo.version)
SDL_GetWMInfo(&wminfo);
HWND WindowHandle = wminfo.window;
if (WindowHandle)
{
SendMessage(WindowHandle, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
SendMessage(WindowHandle, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
}
}
#endif // _WIN32 && !_XBOX
}
//
// ISDL12Window::isFocused
//
// Returns true if this window has input focus.
//
bool ISDL12Window::isFocused() const
{
SDL_PumpEvents();
int app_state = SDL_GetAppState();
return (app_state & SDL_APPINPUTFOCUS) && (app_state & SDL_APPACTIVE);
}
//
// ISDL12Window::getVideoDriverName
//
// Returns the name of the video driver that SDL is currently
// configured to use.
//
std::string ISDL12Window::getVideoDriverName() const
{
char driver[128];
if ((SDL_VideoDriverName(driver, 128)) == NULL)
{
const char* pdrv = getenv("SDL_VIDEODRIVER");
if (pdrv == NULL)
return "";
return std::string(pdrv);
}
return std::string(driver);
}
//
// I_SetSDL12Palette
//
// Helper function for ISDL12Window::setPalette
//
static void I_SetSDL12Palette(SDL_Surface* sdlsurface, const argb_t* palette_colors)
{
if (sdlsurface->format->BitsPerPixel == 8)
{
assert(sdlsurface->format->palette != NULL);
assert(sdlsurface->format->palette->ncolors == 256);
SDL_Color* sdlcolors = sdlsurface->format->palette->colors;
for (int c = 0; c < 256; c++)
{
argb_t color = palette_colors[c];
sdlcolors[c].r = color.getr();
sdlcolors[c].g = color.getg();
sdlcolors[c].b = color.getb();
}
}
}
//
// ISDL12Window::setPalette
//
// Saves the given palette and updates it during refresh.
//
void ISDL12Window::setPalette(const argb_t* palette_colors)
{
lockSurface();
I_SetSDL12Palette(SDL_GetVideoSurface(), palette_colors);
// if (mSDLSoftwareSurface)
// I_SetSDL12Palette(mSDLSoftwareSurface, palette_colors);
getPrimarySurface()->setPalette(palette_colors);
mNeedPaletteRefresh = true;
unlockSurface();
}
//
// I_BuildPixelFormatFromSDLSurface
//
// Helper function that extracts information about the pixel format
// from an SDL_Surface and uses it to initialize a PixelFormat object.
// Note: the SDL_Surface should be locked prior to calling this.
//
static void I_BuildPixelFormatFromSDLSurface(const SDL_Surface* sdlsurface, PixelFormat* format)
{
const SDL_PixelFormat* sdlformat = sdlsurface->format;
uint8_t bpp = sdlformat->BitsPerPixel;
// handle SDL not reporting correct Ashift/Aloss
uint8_t aloss = bpp == 32 ? 0 : 8;
uint8_t ashift = bpp == 32 ? 48 - sdlformat->Rshift - sdlformat->Gshift - sdlformat->Bshift : 0;
// Create the PixelFormat specification
*format = PixelFormat(
bpp,
8 - aloss, 8 - sdlformat->Rloss, 8 - sdlformat->Gloss, 8 - sdlformat->Bloss,
ashift, sdlformat->Rshift, sdlformat->Gshift, sdlformat->Bshift);
}
//
// ISDL12Window::getPixelFormat
//
const PixelFormat* ISDL12Window::getPixelFormat() const
{
static PixelFormat format;
const SDL_Surface* sdl_surface = SDL_GetVideoSurface();
I_BuildPixelFormatFromSDLSurface(sdl_surface, &format);
return &format;
}
//
// ISDL12Window::setMode
//
// Sets the window size to the specified size and frees the existing primary
// surface before instantiating a new primary surface. This function performs
// no sanity checks on the desired video mode.
//
// NOTE: If a hardware surface is obtained or the surface's screen pitch
// will create cache thrashing (tested by pitch & 511 == 0), a SDL software
// surface will be created and used for drawing video frames. This software
// surface is then blitted to the screen at the end of the frame, prior to
// calling SDL_Flip.
//
bool ISDL12Window::setMode(const IVideoMode& video_mode)
{
bool is_windowed = video_mode.window_mode != WINDOW_Fullscreen;
uint32_t flags = 0;
if (video_mode.vsync)
flags |= SDL_HWSURFACE | SDL_DOUBLEBUF;
else
flags |= SDL_SWSURFACE;
if (is_windowed)
{
flags |= SDL_RESIZABLE;
}
else
{
flags |= SDL_FULLSCREEN;
if (video_mode.bpp == 8)
flags |= SDL_HWPALETTE;
}
flags |= SDL_ASYNCBLIT;
#ifdef SDL_GL_SWAP_CONTROL
SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, video_mode.vsync);
#endif
SDL_Surface* sdl_surface = SDL_SetVideoMode(video_mode.width, video_mode.height, video_mode.bpp, flags);
if (sdl_surface == NULL)
{
I_FatalError("I_SetVideoMode: unable to set video mode {}x{}x{} ({}): {}\n",
video_mode.width, video_mode.height, video_mode.bpp, is_windowed ? "windowed" : "fullscreen",
SDL_GetError());
return false;
}
assert(sdl_surface == SDL_GetVideoSurface());
const PixelFormat* format = getPixelFormat();
// just in case SDL couldn't set the exact video mode we asked for...
mVideoMode.width = sdl_surface->w;
mVideoMode.height = sdl_surface->h;
//mVideoMode.bpp = format->getBitsPerPixel();
mVideoMode.bpp = video_mode.bpp;
if ((sdl_surface->flags & SDL_FULLSCREEN) == SDL_FULLSCREEN)
mVideoMode.window_mode = WINDOW_Fullscreen;
else
mVideoMode.window_mode = WINDOW_Windowed;
mVideoMode.vsync = video_mode.vsync;
mVideoMode.stretch_mode = video_mode.stretch_mode;
if (SDL_MUSTLOCK(sdl_surface))
SDL_LockSurface(sdl_surface); // lock prior to accessing pixel format
delete mSurfaceManager;
bool got_hardware_surface = (sdl_surface->flags & SDL_HWSURFACE) == SDL_HWSURFACE;
bool create_software_surface =
(sdl_surface->pitch & 511) == 0 || // pitch is a multiple of 512 (thrashes the cache)
got_hardware_surface; // drawing directly to hardware surfaces is slower
if (create_software_surface)
mSurfaceManager = new ISDL12SoftwareWindowSurfaceManager(mVideoMode.width, mVideoMode.height, format);
else
mSurfaceManager = new ISDL12DirectWindowSurfaceManager(mVideoMode.width, mVideoMode.height, format);
assert(mSurfaceManager != NULL);
assert(getPrimarySurface() != NULL);
if (SDL_MUSTLOCK(sdl_surface))
SDL_UnlockSurface(sdl_surface);
// Tell argb_t the pixel format
if (format->getBitsPerPixel() == 32)
argb_t::setChannels(format->getAPos(), format->getRPos(), format->getGPos(), format->getBPos());
else
{
#if defined(__SWITCH__)
argb_t::setChannels(0, 3, 2, 1);
#else
argb_t::setChannels(3, 2, 1, 0);
#endif
}
// [SL] SDL can create SDL_VIDEORESIZE events in response to SDL_SetVideoMode
// and we need to filter those out.
mIgnoreResize = true;
return true;
}
// ****************************************************************************
// ============================================================================
//
// ISDL12VideoSubsystem class implementation
//
// ============================================================================
//
// ISDL12VideoSubsystem::ISDL12VideoSubsystem
//
// Initializes SDL video and sets a few SDL configuration options.
//
ISDL12VideoSubsystem::ISDL12VideoSubsystem() : IVideoSubsystem()
{
const SDL_version* SDLVersion = SDL_Linked_Version();
if (SDLVersion->major != SDL_MAJOR_VERSION || SDLVersion->minor != SDL_MINOR_VERSION)
{
I_FatalError("SDL version conflict ({}.{}.{} vs {}.{}.{} dll)\n",
SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL,
SDLVersion->major, SDLVersion->minor, SDLVersion->patch);
return;
}
if (SDLVersion->patch != SDL_PATCHLEVEL)
{
Printf(PRINT_WARNING, "SDL version warning (%d.%d.%d vs %d.%d.%d dll)\n",
SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL,
SDLVersion->major, SDLVersion->minor, SDLVersion->patch);
}
if (SDL_InitSubSystem(SDL_INIT_VIDEO) == -1)
{
I_FatalError("Could not initialize SDL video.\n");
return;
}
mVideoCapabilities = new ISDL12VideoCapabilities();
mWindow = new ISDL12Window(640, 480, 8, WINDOW_Windowed, false);
}
//
// ISDL12VideoSubsystem::~ISDL12VideoSubsystem
//
ISDL12VideoSubsystem::~ISDL12VideoSubsystem()
{
delete mWindow;
delete mVideoCapabilities;
SDL_QuitSubSystem(SDL_INIT_VIDEO);
}
#endif // SDL12
VERSION_CONTROL (i_video_sdl12_cpp, "$Id$")

View file

@ -1,257 +0,0 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id$
//
// Copyright (C) 2006-2025 by The Odamex Team.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// SDL 1.2 implementation of the IWindow class
//
//-----------------------------------------------------------------------------
#pragma once
#include "i_sdl.h"
#include "i_video.h"
#ifdef SDL12
// ============================================================================
//
// ISDL12VideoCapabilities class interface
//
// Defines an interface for querying video capabilities. This includes listing
// availible video modes and supported operations.
//
// ============================================================================
class ISDL12VideoCapabilities : public IVideoCapabilities
{
public:
ISDL12VideoCapabilities();
virtual ~ISDL12VideoCapabilities() { }
virtual const IVideoModeList* getSupportedVideoModes() const
{ return &mModeList; }
virtual EDisplayType getDisplayType() const
{
#ifdef GCONSOLE
return DISPLAY_FullscreenOnly;
#else
return DISPLAY_Both;
#endif
}
virtual const IVideoMode& getNativeMode() const
{ return mNativeMode; }
private:
IVideoModeList mModeList;
IVideoMode mNativeMode;
};
// ============================================================================
//
// ISDL12DirectWindowSurfaceManager
//
// Helper class for IWindow to encapsulate the creation of a IWindowSurface
// primary surface and to assist in using it to refresh the window.
//
// This creates a IWindowSurface based on SDL's primary surface.
//
// ============================================================================
class ISDL12DirectWindowSurfaceManager : public IWindowSurfaceManager
{
public:
ISDL12DirectWindowSurfaceManager(uint16_t width, uint16_t height, const PixelFormat* format);
virtual ~ISDL12DirectWindowSurfaceManager();
virtual const IWindowSurface* getWindowSurface() const
{ return mSurface; }
virtual void lockSurface();
virtual void unlockSurface();
virtual void startRefresh();
virtual void finishRefresh();
private:
IWindowSurface* mSurface;
};
// ============================================================================
//
// ISDL12SoftwareWindowSurfaceManager
//
// Helper class for IWindow to encapsulate the creation of a IWindowSurface
// primary surface and to assist in using it to refresh the window.
//
//
// ============================================================================
class ISDL12SoftwareWindowSurfaceManager : public IWindowSurfaceManager
{
public:
ISDL12SoftwareWindowSurfaceManager(uint16_t width, uint16_t height, const PixelFormat* format);
virtual ~ISDL12SoftwareWindowSurfaceManager();
virtual const IWindowSurface* getWindowSurface() const
{ return mSurface; }
virtual void lockSurface();
virtual void unlockSurface();
virtual void startRefresh();
virtual void finishRefresh();
private:
SDL_Surface* mSDLSoftwareSurface;
IWindowSurface* mSurface;
};
// ============================================================================
//
// ISDL12Window class interface
//
// ============================================================================
class ISDL12Window : public IWindow
{
public:
ISDL12Window(uint16_t width, uint16_t height, uint8_t bpp, EWindowMode window_mode, bool vsync);
virtual ~ISDL12Window();
virtual const IWindowSurface* getPrimarySurface() const
{
if (mSurfaceManager)
return mSurfaceManager->getWindowSurface();
return NULL;
}
virtual IWindowSurface* getPrimarySurface()
{
return const_cast<IWindowSurface*>(static_cast<const ISDL12Window&>(*this).getPrimarySurface());
}
virtual uint16_t getWidth() const
{ return mVideoMode.width; }
virtual uint16_t getHeight() const
{ return mVideoMode.height; }
virtual uint8_t getBitsPerPixel() const
{ return mVideoMode.bpp; }
virtual int getBytesPerPixel() const
{ return mVideoMode.bpp >> 3; }
virtual const IVideoMode& getVideoMode() const
{ return mVideoMode; }
virtual const PixelFormat* getPixelFormat() const;
virtual bool setMode(const IVideoMode& video_mode);
virtual bool isFullScreen() const
{ return mVideoMode.window_mode != WINDOW_Windowed; }
virtual EWindowMode getWindowMode() const
{ return mVideoMode.window_mode; }
virtual bool isFocused() const;
virtual bool usingVSync() const
{ return mVideoMode.vsync; }
virtual void enableRefresh()
{ mBlit = true; }
virtual void disableRefresh()
{
mBlit = false;
mSurfaceManager->lockSurface();
mSurfaceManager->getWindowSurface()->clear();
mSurfaceManager->finishRefresh();
mSurfaceManager->unlockSurface();
}
virtual void startRefresh();
virtual void finishRefresh();
virtual void lockSurface();
virtual void unlockSurface();
virtual void setWindowTitle(const std::string& str = "");
virtual void setWindowIcon();
virtual std::string getVideoDriverName() const;
virtual void setPalette(const argb_t* palette);
private:
// disable copy constructor and assignment operator
ISDL12Window(const ISDL12Window&);
ISDL12Window& operator=(const ISDL12Window&);
void getEvents();
IWindowSurfaceManager* mSurfaceManager;
IVideoMode mVideoMode;
bool mNeedPaletteRefresh;
bool mBlit;
bool mIgnoreResize;
int16_t mLocks;
};
// ****************************************************************************
// ============================================================================
//
// ISDL12VideoSubsystem class interface
//
// Provides intialization and shutdown mechanics for the video subsystem.
// This is really an abstract factory pattern as it instantiates a family
// of concrete types.
//
// ============================================================================
class ISDL12VideoSubsystem : public IVideoSubsystem
{
public:
ISDL12VideoSubsystem();
virtual ~ISDL12VideoSubsystem();
virtual const IVideoCapabilities* getVideoCapabilities() const
{ return mVideoCapabilities; }
virtual const IWindow* getWindow() const
{ return mWindow; }
private:
const IVideoCapabilities* mVideoCapabilities;
IWindow* mWindow;
};
#endif // SDL12

View file

@ -44,15 +44,11 @@
// [Russell] - Just for windows, display the icon in the system menu and alt-tab display
#include "win32inc.h"
#if defined(_WIN32) && !defined(_XBOX)
#if defined(_WIN32)
#include <SDL_syswm.h>
#include "resource.h"
#endif // WIN32
#ifdef _XBOX
#include "i_xbox.h"
#endif
EXTERN_CVAR (vid_fullscreen)
EXTERN_CVAR (vid_widescreen)
EXTERN_CVAR (vid_pillarbox)
@ -395,7 +391,7 @@ ISDL20Window::ISDL20Window(uint16_t width, uint16_t height, uint8_t bpp, EWindow
{
setRendererDriver();
const char* driver_name = getRendererDriver();
Printf(PRINT_HIGH, "V_Init: rendering mode \"%s\"\n", driver_name);
PrintFmt(PRINT_HIGH, "V_Init: rendering mode \"{}\"\n", driver_name);
SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");
@ -664,7 +660,7 @@ void ISDL20Window::setWindowTitle(const std::string& str)
//
void ISDL20Window::setWindowIcon()
{
#if defined(_WIN32) && !defined(_XBOX)
#if defined(_WIN32)
// [SL] Use Win32-specific code to make use of multiple-icon sizes
// stored in the executable resources.
//
@ -686,9 +682,9 @@ void ISDL20Window::setWindowIcon()
SendMessage(WindowHandle, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
}
}
#endif // _WIN32 && !_XBOX
#endif // _WIN32
#if !defined(_WIN32) && !defined(_XBOX)
#if !defined(_WIN32)
SDL_Surface* icon_surface = SDL_CreateRGBSurfaceFrom(
(void*)app_icon.pixel_data, app_icon.width, app_icon.height,
app_icon.bytes_per_pixel * 8, app_icon.width * app_icon.bytes_per_pixel,
@ -696,7 +692,7 @@ void ISDL20Window::setWindowIcon()
SDL_SetWindowIcon(mSDLWindow, icon_surface);
SDL_FreeSurface(icon_surface);
#endif // !_WIN32 && !_XBOX
#endif // !_WIN32
}

View file

@ -61,6 +61,7 @@ argb_t CL_GetPlayerColor(player_t*);
EXTERN_CVAR(am_followplayer)
static int lockglow = 0;
static int bossglow = 0;
EXTERN_CVAR(am_rotate)
EXTERN_CVAR(am_overlay)
@ -194,6 +195,7 @@ typedef struct
// vector graphics for the automap for things.
std::vector<mline_t> thintriangle_guy;
std::vector<mline_t> thinrectangle_guy;
std::vector<mline_t> hordeboss_guy;
am_default_colors_t AutomapDefaultColors;
am_colors_t AutomapDefaultCurrentColors;
@ -270,21 +272,21 @@ void AM_minOutWindowScale();
BEGIN_COMMAND(am_grid)
{
grid = !grid;
Printf(PRINT_HIGH, "%s\n", grid ? GStrings(AMSTR_GRIDON) : GStrings(AMSTR_GRIDOFF));
PrintFmt(PRINT_HIGH, "{}\n", grid ? GStrings(AMSTR_GRIDON) : GStrings(AMSTR_GRIDOFF));
}
END_COMMAND(am_grid)
BEGIN_COMMAND(am_setmark)
{
AM_addMark();
Printf(PRINT_HIGH, "%s %d\n", GStrings(AMSTR_MARKEDSPOT), markpointnum);
PrintFmt(PRINT_HIGH, "{} {}\n", GStrings(AMSTR_MARKEDSPOT), markpointnum);
}
END_COMMAND(am_setmark)
BEGIN_COMMAND(am_clearmarks)
{
AM_clearMarks();
Printf(PRINT_HIGH, "%s\n", GStrings(AMSTR_MARKSCLEARED));
PrintFmt(PRINT_HIGH, "{}\n", GStrings(AMSTR_MARKSCLEARED));
}
END_COMMAND(am_clearmarks)
@ -304,9 +306,9 @@ END_COMMAND(am_big)
BEGIN_COMMAND(am_togglefollow)
{
am_followplayer = !am_followplayer;
f_oldloc.x = MAXINT;
Printf(PRINT_HIGH, "%s\n",
am_followplayer ? GStrings(AMSTR_FOLLOWON) : GStrings(AMSTR_FOLLOWOFF));
f_oldloc.x = limits::MAXINT;
PrintFmt(PRINT_HIGH, "{}\n",
am_followplayer ? GStrings(AMSTR_FOLLOWON) : GStrings(AMSTR_FOLLOWOFF));
}
END_COMMAND(am_togglefollow)
@ -383,8 +385,8 @@ void AM_addMark()
//
void AM_findMinMaxBoundaries()
{
M_SetVec2Fixed64(&min, MAXLONG, MAXLONG);
M_SetVec2Fixed64(&max, -MAXLONG, -MAXLONG);
M_SetVec2Fixed64(&min, limits::MAXFIXED64, limits::MAXFIXED64);
M_SetVec2Fixed64(&max, limits::MINFIXED64, limits::MINFIXED64);
for (const auto [x, y]: R_GetVertices())
{
@ -419,7 +421,7 @@ void AM_changeWindowLoc()
if (m_paninc.x || m_paninc.y)
{
am_followplayer.Set(0.0f);
f_oldloc.x = MAXINT;
f_oldloc.x = limits::MAXINT;
}
M_AddVec2Fixed64(&m_ll, &m_paninc, &m_ll);
@ -446,6 +448,7 @@ void AM_initVariables()
thintriangle_guy.clear();
thinrectangle_guy.clear();
hordeboss_guy.clear();
mline_t ml;
@ -466,12 +469,30 @@ void AM_initVariables()
ADD_TO_VEC(thinrectangle_guy, -1, -1, -1, 1)
ADD_TO_VEC(thinrectangle_guy, -1, 1, 1, 1)
static const OLumpName bossicon = "OBOSSMAP";
const auto hordeboss_lines = AM_ParseVectorLump(bossicon);
if (!hordeboss_lines)
{
switch (hordeboss_lines.error())
{
case am_lump_parse_error_t::LUMP_NOT_FOUND:
DPrintFmt("Horde boss automap icon lump \"{}\" could not be found", bossicon);
break;
default:
DPrintFmt("Error while parsing horde boss automap icon lump \"{}\"", bossicon);
}
}
else
{
hordeboss_guy = hordeboss_lines.value();
}
#undef ADD_TO_VEC
#undef L
automapactive = true;
f_oldloc.x = MAXINT;
f_oldloc.x = limits::MAXINT;
amclock = 0;
M_SetVec2Fixed64(&m_wh, FTOM(I_GetSurfaceWidth()), FTOM(I_GetSurfaceHeight()));
@ -919,6 +940,15 @@ void AM_doFollowPlayer()
m_ll.y + m_wh.y);
}
struct
{
std::array<uint8_t, 3> reddoor;
std::array<uint8_t, 3> bluedoor;
std::array<uint8_t, 3> yellowdoor;
std::array<uint8_t, 3> multidoor;
} doorColors;
//
// Updates on Game Tick
//
@ -934,6 +964,77 @@ void AM_Ticker()
lockglow++;
else
lockglow = 0;
if (bossglow < 60)
bossglow++;
else
bossglow = 0;
const std::array<uint8_t,3> baseDoorColor = {
gameinfo.currentAutomapColors.LockedColor.rgb.getr(),
gameinfo.currentAutomapColors.LockedColor.rgb.getg(),
gameinfo.currentAutomapColors.LockedColor.rgb.getb()
};
if (am_usecustomcolors || am_showlocked)
{
const auto lerp = [](uint8_t a, uint8_t b, int t, int max) -> uint8_t
{
return static_cast<uint8_t>(a + (b - a) * t / max);
};
const auto lerp3 = [&lerp](const std::array<uint8_t,3>& a,
const std::array<uint8_t,3>& b,
int t, int max)
{
return std::array<uint8_t, 3>{
lerp(a[0], b[0], t, max),
lerp(a[1], b[1], t, max),
lerp(a[2], b[2], t, max)
};
};
const auto pulse = [&baseDoorColor, &lerp3](const std::array<uint8_t, 3>& color) -> std::array<uint8_t, 3>
{
if (lockglow < 30)
{
return lerp3(baseDoorColor, color, lockglow, 30);
}
else if (lockglow < 60)
{
return lerp3(baseDoorColor, color, 60 - lockglow, 30);
}
else
{
return baseDoorColor;
}
};
static constexpr std::array<uint8_t, 3> red = {255, 0, 0};
static constexpr std::array<uint8_t, 3> blue = {0, 0, 255};
static constexpr std::array<uint8_t, 3> yellow = {255, 255, 0};
doorColors.reddoor = pulse(red);
doorColors.bluedoor = pulse(blue);
doorColors.yellowdoor = pulse(yellow);
static constexpr std::array<std::array<uint8_t,3>, 3> seq = {
red, blue, yellow
};
const int segment = (lockglow / 30) % 3;
const int next = (segment + 1) % 3;
const int t = lockglow % 30;
doorColors.multidoor = lerp3(seq[segment], seq[next], t, 30);
}
else
{
doorColors.reddoor = baseDoorColor;
doorColors.bluedoor = baseDoorColor;
doorColors.yellowdoor = baseDoorColor;
doorColors.multidoor = baseDoorColor;
}
}
//
@ -1354,49 +1455,56 @@ void AM_drawWalls()
AM_drawMline(&l, gameinfo.currentAutomapColors.TSWallColor);
}
// NES - Locked doors glow from a predefined color to either blue,
// yellow, or red.
if (map_format.getZDoom())
{
if (line.special == Door_LockedRaise)
if (line.special == Door_LockedRaise || line.special == Generic_Door)
{
// NES - Locked doors glow from a predefined color to either blue,
// yellow, or red.
r = gameinfo.currentAutomapColors.LockedColor.rgb.getr();
g = gameinfo.currentAutomapColors.LockedColor.rgb.getg();
b = gameinfo.currentAutomapColors.LockedColor.rgb.getb();
if (am_usecustomcolors || am_showlocked)
const short lock = line.special == Door_LockedRaise ? line.args[3] : line.args[4];
switch (lock)
{
if (line.args[3] == (zk_blue_card | zk_blue))
{
rdif = (0 - r) / 30;
gdif = (0 - g) / 30;
bdif = (255 - b) / 30;
}
else if (line.args[3] == (zk_yellow_card | zk_yellow))
{
rdif = (255 - r) / 30;
gdif = (255 - g) / 30;
bdif = (0 - b) / 30;
}
else
{
rdif = (255 - r) / 30;
gdif = (0 - g) / 30;
bdif = (0 - b) / 30;
}
if (lockglow < 30)
{
r += static_cast<int>(rdif) * lockglow;
g += static_cast<int>(gdif) * lockglow;
b += static_cast<int>(bdif) * lockglow;
}
else if (lockglow < 60)
{
r += static_cast<int>(rdif) * (60 - lockglow);
g += static_cast<int>(gdif) * (60 - lockglow);
b += static_cast<int>(bdif) * (60 - lockglow);
}
case zk_blue_card:
case zk_blue:
case zk_blue_skull:
case zk_bluex:
r = doorColors.bluedoor[0];
g = doorColors.bluedoor[1];
b = doorColors.bluedoor[2];
break;
case zk_yellow_card:
case zk_yellow:
case zk_yellow_skull:
case zk_yellowx:
r = doorColors.yellowdoor[0];
g = doorColors.yellowdoor[1];
b = doorColors.yellowdoor[2];
break;
case zk_red_card:
case zk_red:
case zk_red_skull:
case zk_redx:
r = doorColors.reddoor[0];
g = doorColors.reddoor[1];
b = doorColors.reddoor[2];
break;
case zk_all:
case zk_any:
case zk_each_color:
r = doorColors.multidoor[0];
g = doorColors.multidoor[1];
b = doorColors.multidoor[2];
break;
case zk_none:
r = gameinfo.currentAutomapColors.CDWallColor.rgb.getr();
g = gameinfo.currentAutomapColors.CDWallColor.rgb.getg();
b = gameinfo.currentAutomapColors.CDWallColor.rgb.getb();
break;
default:
r = gameinfo.currentAutomapColors.LockedColor.rgb.getr();
g = gameinfo.currentAutomapColors.LockedColor.rgb.getg();
b = gameinfo.currentAutomapColors.LockedColor.rgb.getb();
break;
}
AM_drawMline(&l, AM_BestColor(pal->basecolors, r, g, b));
@ -1408,42 +1516,31 @@ void AM_drawWalls()
{
// NES - Locked doors glow from a predefined color to either blue,
// yellow, or red.
r = gameinfo.currentAutomapColors.LockedColor.rgb.getr();
g = gameinfo.currentAutomapColors.LockedColor.rgb.getg();
b = gameinfo.currentAutomapColors.LockedColor.rgb.getb();
if (am_usecustomcolors || am_showlocked)
if (P_IsCompatibleMultiKeyDoorLine(line.special))
{
r = doorColors.multidoor[0];
g = doorColors.multidoor[1];
b = doorColors.multidoor[2];
}
else
{
if (P_IsCompatibleBlueDoorLine(line.special))
{
rdif = (0 - r) / 30;
gdif = (0 - g) / 30;
bdif = (255 - b) / 30;
r = doorColors.bluedoor[0];
g = doorColors.bluedoor[1];
b = doorColors.bluedoor[2];
}
else if (P_IsCompatibleYellowDoorLine(line.special))
{
rdif = (255 - r) / 30;
gdif = (255 - g) / 30;
bdif = (0 - b) / 30;
r = doorColors.yellowdoor[0];
g = doorColors.yellowdoor[1];
b = doorColors.yellowdoor[2];
}
else
{
rdif = (255 - r) / 30;
gdif = (0 - g) / 30;
bdif = (0 - b) / 30;
}
if (lockglow < 30)
{
r += static_cast<int>(rdif) * lockglow;
g += static_cast<int>(gdif) * lockglow;
b += static_cast<int>(bdif) * lockglow;
}
else if (lockglow < 60)
{
r += static_cast<int>(rdif) * (60 - lockglow);
g += static_cast<int>(gdif) * (60 - lockglow);
b += static_cast<int>(bdif) * (60 - lockglow);
r = doorColors.reddoor[0];
g = doorColors.reddoor[1];
b = doorColors.reddoor[2];
}
}
@ -1512,7 +1609,7 @@ void AM_rotatePoint(mpoint_t& pt)
pt.y += y;
}
void AM_drawLineCharacter(const std::vector<mline_t>& lineguy, fixed64_t scale,
void AM_drawLineCharacter(nonstd::span<const mline_t> lineguy, fixed64_t scale,
angle_t angle, am_color_t color, fixed64_t x, fixed64_t y)
{
for (const auto& mline : lineguy)
@ -1670,7 +1767,7 @@ void AM_drawPlayers()
}
}
bool AM_actorIsKey(AActor* t)
bool AM_actorIsKey(const AActor* t)
{
if (t->sprite == SPR_BKEY || t->sprite == SPR_YKEY || t->sprite == SPR_RKEY ||
t->sprite == SPR_BSKU || t->sprite == SPR_YSKU || t->sprite == SPR_RSKU)
@ -1681,7 +1778,7 @@ bool AM_actorIsKey(AActor* t)
return false;
}
am_color_t AM_getKeyColor(AActor *t)
am_color_t AM_getKeyColor(const AActor *t)
{
am_color_t color = gameinfo.currentAutomapColors.ThingColor;
const argb_t* palette = V_GetDefaultPalette()->colors;
@ -1696,123 +1793,177 @@ am_color_t AM_getKeyColor(AActor *t)
return color;
}
void AM_drawEasyKeys()
void AM_drawEasyKey(const AActor* t)
{
for (const sector_t& sector : R_GetSectors())
if (AM_actorIsKey(t))
{
AActor* t = sector.thinglist;
while (t)
mpoint_t p;
M_SetVec2Fixed64(&p, FIXED2FIXED64(t->x), FIXED2FIXED64(t->y));
const am_color_t key_color = AM_getKeyColor(t);
AM_drawLineCharacter(gameinfo.easyKey, FIXED2FIXED64(t->radius), 0, key_color, p.x, p.y);
}
}
void AM_drawHordeBoss(const AActor* t)
{
OInterpolation& oi = OInterpolation::getInstance();
if (t->oflags & MFO_BOSSPOOL)
{
fixed_t thingx;
fixed_t thingy;
if (oi.enabled())
{
if (AM_actorIsKey(t))
{
mpoint_t p;
M_SetVec2Fixed64(&p, FIXED2FIXED64(t->x), FIXED2FIXED64(t->y));
const am_color_t key_color = AM_getKeyColor(t);
AM_drawLineCharacter(gameinfo.easyKey, FIXED2FIXED64(t->radius), 0, key_color, p.x, p.y);
}
t = t->snext;
thingx = t->prevx + FixedMul(t->x - t->prevx, render_lerp_amount);
thingy = t->prevy + FixedMul(t->y - t->prevy, render_lerp_amount);
}
else
{
thingx = t->x;
thingy = t->y;
}
mpoint_t p;
M_SetVec2Fixed64(&p, FIXED2FIXED64(thingx), FIXED2FIXED64(thingy));
if (am_rotate)
AM_rotatePoint(p);
const palette_t* palette = V_GetDefaultPalette();
am_color_t gold = AM_GetColorFromString(palette->colors, "light goldenrod yellow");
auto r = gold.rgb.getr();
auto g = gold.rgb.getg();
auto b = gold.rgb.getb();
float rdif = (255 - r) / 30;
float gdif = (0 - g) / 30;
float bdif = (0 - b) / 30;
if (bossglow < 20)
{
r += static_cast<int>(rdif) * bossglow;
g += static_cast<int>(gdif) * bossglow;
b += static_cast<int>(bdif) * bossglow;
}
else if (bossglow < 40)
{
r += static_cast<int>(rdif) * (40 - bossglow);
g += static_cast<int>(gdif) * (40 - bossglow);
b += static_cast<int>(bdif) * (40 - bossglow);
}
AM_drawLineCharacter(hordeboss_guy, FIXED2FIXED64(t->radius), 0, AM_BestColor(palette->basecolors, r, g, b),
p.x, p.y);
}
}
void AM_drawCheatThing(const AActor* t)
{
OInterpolation& oi = OInterpolation::getInstance();
mpoint_t p;
fixed_t thingx;
fixed_t thingy;
fixed_t tangle;
if (oi.enabled())
{
thingx = t->prevx + FixedMul(t->x - t->prevx, render_lerp_amount);
thingy = t->prevy + FixedMul(t->y - t->prevy, render_lerp_amount);
tangle = t->prevangle + FixedMul(t->angle - t->prevangle, render_lerp_amount);
}
else
{
thingx = t->x;
thingy = t->y;
tangle = t->angle;
}
M_SetVec2Fixed64(&p, FIXED2FIXED64(thingx), FIXED2FIXED64(thingy));
angle_t rotate_angle = 0;
angle_t triangle_angle = tangle;
if (am_rotate)
{
AM_rotatePoint(p);
fixed_t conangle;
if (oi.enabled())
{
conangle = displayplayer().camera->prevangle +
FixedMul(displayplayer().camera->angle -
displayplayer().camera->prevangle,
render_lerp_amount);
}
else
{
conangle = displayplayer().camera->angle;
}
rotate_angle = ANG90 - conangle;
triangle_angle += rotate_angle;
}
if (AM_actorIsKey(t))
{
if (!G_GetCurrentSkill().easy_key)
{
const am_color_t key_color = AM_getKeyColor(t);
AM_drawLineCharacter(gameinfo.cheatKey, FIXED2FIXED64(t->radius), 0, key_color, p.x,
p.y);
}
}
else
{
am_color_t color = gameinfo.currentAutomapColors.ThingColor;
AM_drawLineCharacter(thintriangle_guy, FIXED2FIXED64(t->radius), triangle_angle, color,
p.x, p.y);
if (t->flags & MF_MISSILE)
{
color = gameinfo.currentAutomapColors.ThingColor_Projectile;
}
else if (t->flags & MF_SPECIAL)
{
if (t->flags & MF_COUNTITEM)
color = gameinfo.currentAutomapColors.ThingColor_CountItem;
else
color = gameinfo.currentAutomapColors.ThingColor_Item;
}
else if (t->flags & MF_SOLID && t->flags & MF_SHOOTABLE)
{
if (t->flags & MF_FRIEND)
color = gameinfo.currentAutomapColors.ThingColor_Friend;
else if (t->flags & MF_COUNTKILL)
color = gameinfo.currentAutomapColors.ThingColor_Monster;
else
color = gameinfo.currentAutomapColors.ThingColor_NoCountMonster;
}
AM_drawLineCharacter(thinrectangle_guy, FIXED2FIXED64(t->radius), rotate_angle, color,
p.x, p.y);
}
}
void AM_drawThings()
{
OInterpolation& oi = OInterpolation::getInstance();
for (const sector_t& sector : R_GetSectors())
{
AActor* t = sector.thinglist;
const AActor* t = sector.thinglist;
while (t)
{
mpoint_t p;
fixed_t thingx;
fixed_t thingy;
fixed_t tangle;
if (oi.enabled())
{
thingx = t->prevx + FixedMul(t->x - t->prevx, render_lerp_amount);
thingy = t->prevy + FixedMul(t->y - t->prevy, render_lerp_amount);
tangle = t->prevangle + FixedMul(t->angle - t->prevangle, render_lerp_amount);
}
else
{
thingx = t->x;
thingy = t->y;
tangle = t->angle;
}
M_SetVec2Fixed64(&p, FIXED2FIXED64(thingx), FIXED2FIXED64(thingy));
angle_t rotate_angle = 0;
angle_t triangle_angle = tangle;
if (am_rotate)
{
AM_rotatePoint(p);
fixed_t conangle;
if (oi.enabled())
{
conangle = displayplayer().camera->prevangle +
FixedMul(displayplayer().camera->angle -
displayplayer().camera->prevangle,
render_lerp_amount);
}
else
{
conangle = displayplayer().camera->angle;
}
rotate_angle = ANG90 - conangle;
triangle_angle += rotate_angle;
}
if (AM_actorIsKey(t))
{
if (!G_GetCurrentSkill().easy_key)
{
const am_color_t key_color = AM_getKeyColor(t);
AM_drawLineCharacter(gameinfo.cheatKey, FIXED2FIXED64(t->radius), 0, key_color, p.x,
p.y);
}
}
else
{
am_color_t color = gameinfo.currentAutomapColors.ThingColor;
AM_drawLineCharacter(thintriangle_guy, FIXED2FIXED64(t->radius), triangle_angle, color,
p.x, p.y);
if (t->flags & MF_MISSILE)
{
color = gameinfo.currentAutomapColors.ThingColor_Projectile;
}
else if (t->flags & MF_SPECIAL)
{
if (t->flags & MF_COUNTITEM)
color = gameinfo.currentAutomapColors.ThingColor_CountItem;
else
color = gameinfo.currentAutomapColors.ThingColor_Item;
}
else if (t->flags & MF_SOLID && t->flags & MF_SHOOTABLE)
{
if (t->flags & MF_FRIEND)
color = gameinfo.currentAutomapColors.ThingColor_Friend;
else if (t->flags & MF_COUNTKILL)
color = gameinfo.currentAutomapColors.ThingColor_Monster;
else
color = gameinfo.currentAutomapColors.ThingColor_NoCountMonster;
}
AM_drawLineCharacter(thinrectangle_guy, FIXED2FIXED64(t->radius), rotate_angle, color,
p.x, p.y);
}
if (G_IsHordeMode())
AM_drawHordeBoss(t);
if (G_GetCurrentSkill().easy_key)
AM_drawEasyKey(t);
if (am_cheating == 2)
AM_drawCheatThing(t);
t = t->snext;
}
}
@ -1922,9 +2073,7 @@ void AM_Drawer()
AM_drawWalls();
AM_drawPlayers();
if (G_GetCurrentSkill().easy_key)
AM_drawEasyKeys();
if (am_cheating == 2)
if (G_IsHordeMode() || G_GetCurrentSkill().easy_key || (am_cheating == 2))
AM_drawThings();
if (!(viewactive && am_overlay < 2))

View file

@ -72,7 +72,7 @@ OBinding DefaultBindings[] =
{"s", "+back"},
{"a", "+moveleft"},
{"d", "+moveright"},
#ifdef _XBOX
#ifdef GCONSOLE
{"hat1right", "messagemode2"},
{"hat1left", "spynext"},
{"hat1up", "messagemode"},
@ -579,8 +579,8 @@ END_COMMAND(bind)
BEGIN_COMMAND(unbind)
{
if (argc < 2) {
Printf(PRINT_WARNING, "Unbinds a key. \"all\" unbinds every key.\n");
Printf(PRINT_WARNING, "Usage: unbind <key>\n");
PrintFmt(PRINT_WARNING, "Unbinds a key. \"all\" unbinds every key.\n");
PrintFmt(PRINT_WARNING, "Usage: unbind <key>\n");
return;
}
@ -603,8 +603,8 @@ BEGIN_COMMAND(undoublebind)
{
if (argc < 2)
{
Printf(PRINT_WARNING, "Unbinds a doublekey. \"all\" unbinds every doublebind key.\n");
Printf(PRINT_WARNING, "Usage: undoublebind <key>\n");
PrintFmt(PRINT_WARNING, "Unbinds a doublekey. \"all\" unbinds every doublebind key.\n");
PrintFmt(PRINT_WARNING, "Usage: undoublebind <key>\n");
return;
}
@ -626,8 +626,8 @@ BEGIN_COMMAND(unambind)
{
if (argc < 2)
{
Printf(PRINT_WARNING, "Unbinds an automap key. \"all\" unbinds every automap key.\n");
Printf(PRINT_WARNING, "Usage: unambind <key>\n");
PrintFmt(PRINT_WARNING, "Unbinds an automap key. \"all\" unbinds every automap key.\n");
PrintFmt(PRINT_WARNING, "Usage: unambind <key>\n");
return;
}
@ -652,9 +652,9 @@ BEGIN_COMMAND(unnetdemobind)
{
if (argc < 2)
{
Printf(PRINT_WARNING,
"Unbinds a netdemo key. \"all\" unbinds every existing netdemo key.\n");
Printf(PRINT_WARNING, "Usage: unnetdemobind <key>\n");
PrintFmt(PRINT_WARNING,
"Unbinds a netdemo key. \"all\" unbinds every existing netdemo key.\n");
PrintFmt(PRINT_WARNING, "Usage: unnetdemobind <key>\n");
return;
}

View file

@ -638,7 +638,7 @@ void ConsoleHistory::movePositionDown()
void ConsoleHistory::dump()
{
for (const auto& it : history)
Printf(PRINT_HIGH, " %s\n", it);
PrintFmt(PRINT_HIGH, " {}\n", it);
}
class ConsoleCompletions
@ -1163,6 +1163,10 @@ void C_AddNotifyString(int printlevel, const char* color_code, const char* sourc
if (printlevel == PRINT_FILTERCHAT)
return;
// Do not display filtered normal messages
if (printlevel == PRINT_FILTERHIGH)
return;
const int width = I_GetSurfaceWidth() / V_TextScaleXAmount();
if (addtype == APPENDLINE && NotifyStrings[NUMNOTIFIES-1].printlevel == printlevel)
@ -1211,15 +1215,14 @@ void C_AddNotifyString(int printlevel, const char* color_code, const char* sourc
// Prints the given string to stdout, stripping away any color markup
// escape codes.
//
static size_t C_PrintStringStdOut(const char* str)
static size_t C_PrintStringStdOut(std::string str)
{
std::string sanitized_str(str);
StripColorCodes(sanitized_str);
StripColorCodes(str);
fmt::print("{}", sanitized_str);
fmt::print("{}", str);
fflush(stdout);
return sanitized_str.length();
return str.length();
}
@ -1244,6 +1247,9 @@ static size_t C_PrintString(int printlevel, const char* color_code, const char*
if (printlevel == PRINT_FILTERCHAT)
printlevel = PRINT_CHAT;
if (printlevel == PRINT_FILTERHIGH)
printlevel = PRINT_HIGH;
const char* line_start = outline;
const char* line_end = line_start;
@ -1344,7 +1350,7 @@ size_t C_BasePrint(const int printlevel, const char* color_code, const std::stri
}
if (print_stdout && gamestate != GS_FORCEWIPE)
C_PrintStringStdOut(newStr.c_str());
C_PrintStringStdOut(newStr);
if (!con_coloredmessages)
StripColorCodes(newStr);
@ -2008,7 +2014,7 @@ static bool C_HandleKey(const event_t* ev)
History.addString(text);
History.resetPosition();
Printf(127, "]%s\n", text);
PrintFmt(127, "]{}\n", text);
AddCommandString(text);
CmdLine.clear();
}
@ -2139,7 +2145,7 @@ static bool C_HandleKey(const event_t* ev)
History.addString(CmdLine.text);
History.resetPosition();
Printf(127, "]%s\n", CmdLine.text.c_str());
PrintFmt(127, "]{}\n", CmdLine.text.c_str());
AddCommandString(CmdLine.text.c_str());
CmdLine.clear();
CmdCompletions.clear();
@ -2242,7 +2248,7 @@ BEGIN_COMMAND(echo)
if (argc > 1)
{
const std::string str = C_ArgCombine(argc - 1, (const char **)(argv + 1));
Printf(PRINT_HIGH, "%s\n", str.c_str());
PrintFmt(PRINT_HIGH, "{}\n", str);
}
}
END_COMMAND(echo)
@ -2285,7 +2291,7 @@ void C_MidPrint(const char *msg, player_t *p, int msgtime)
char *newmsg = strdup(str.c_str());
Printf(PRINT_HIGH, "%s\n", newmsg);
PrintFmt(PRINT_HIGH, "{}\n", newmsg);
midprinting = false;
if ( (MidMsg = V_BreakLines(I_GetSurfaceWidth() / V_TextScaleXAmount(), (byte *)newmsg)) )

View file

@ -315,7 +315,7 @@ CVAR (joy_turnaxis, "2", "", CVARTYPE_FLOAT, CVAR_CLIENTARCHIVE | CVAR_NOENABLED
CVAR (joy_lookaxis, "3", "", CVARTYPE_FLOAT, CVAR_CLIENTARCHIVE | CVAR_NOENABLEDISABLE)
CVAR (joy_sensitivity, "10.0", "", CVARTYPE_FLOAT, CVAR_CLIENTARCHIVE | CVAR_NOENABLEDISABLE)
CVAR (joy_fastsensitivity, "15.0", "", CVARTYPE_FLOAT, CVAR_CLIENTARCHIVE | CVAR_NOENABLEDISABLE)
CVAR (joy_freelook, "0", "", CVARTYPE_FLOAT, CVAR_CLIENTARCHIVE)
CVAR_FUNC_DECL (joy_freelook, "0", "Look up or down with the joystick", CVARTYPE_BOOL, CVAR_CLIENTARCHIVE)
CVAR (joy_invert, "0", "", CVARTYPE_FLOAT, CVAR_CLIENTARCHIVE)
CVAR_RANGE (joy_deadzone, "0.20", "", CVARTYPE_FLOAT, CVAR_CLIENTARCHIVE | CVAR_NOENABLEDISABLE, 0.0f, 0.75f)
@ -386,8 +386,8 @@ CVAR( cl_forcedownload, "0", "Forces the client to download the last WAD file
// Client Preferences
// ------------------
#ifdef _XBOX // Because Xbox players may be unable to communicate for now -- Hyper_Eye
CVAR_FUNC_DECL( cl_name, "Xbox Player", "",
#ifdef GCONSOLE // Because Xbox players may be unable to communicate for now -- Hyper_Eye
CVAR_FUNC_DECL( cl_name, "Console Player", "",
CVARTYPE_STRING, CVAR_USERINFO | CVAR_CLIENTARCHIVE | CVAR_NOENABLEDISABLE)
#else
CVAR_FUNC_DECL( cl_name, "Player", "",
@ -424,6 +424,9 @@ CVAR(in_autosr50, "1", "+strafe activates automatic SR50", CVARTYPE_BOOL,
CVAR( cl_showspawns, "0", "Show spawn points as particle fountains",
CVARTYPE_BOOL, CVAR_CLIENTARCHIVE | CVAR_LATCH)
CVAR_FUNC_DECL( cl_showfriends, "0", "Show an indicator on friendly monsters.",
CVARTYPE_BOOL, CVAR_CLIENTARCHIVE)
// Netdemo Preferences
// --------------------
@ -598,7 +601,7 @@ CVAR_RANGE(hud_extendedinfo, "0",
"Show kills, items, and secrets:\n// 0: Off\n// 1: DIGFONT\n// 2: SMALLFONT\n// 3: DIGFONT, vertical arrangement\n// 4: SMALLFONT, vertical arrangement",
CVARTYPE_INT, CVAR_CLIENTARCHIVE | CVAR_NOENABLEDISABLE, 0.0, 4.0)
#ifdef _XBOX
#ifdef GCONSOLE
CVAR (chatmacro0, "Hi.", "", CVARTYPE_STRING, CVAR_CLIENTARCHIVE | CVAR_NOENABLEDISABLE) // A
CVAR (chatmacro1, "I'm ready to kick butt!", "", CVARTYPE_STRING, CVAR_CLIENTARCHIVE | CVAR_NOENABLEDISABLE) // B
CVAR (chatmacro2, "Help!", "", CVARTYPE_STRING, CVAR_CLIENTARCHIVE | CVAR_NOENABLEDISABLE) // X
@ -608,7 +611,7 @@ CVAR (chatmacro5, "Yes", "", CVARTYPE_STRING, CVAR_CLIENTARCHIVE | CVAR_NOENABLE
CVAR (chatmacro6, "I'll take care of it.", "", CVARTYPE_STRING, CVAR_CLIENTARCHIVE | CVAR_NOENABLEDISABLE) // Left Trigger
CVAR (chatmacro7, "Come here!", "", CVARTYPE_STRING, CVAR_CLIENTARCHIVE | CVAR_NOENABLEDISABLE) // Right Trigger
CVAR (chatmacro8, "Thanks for the game. Bye.", "", CVARTYPE_STRING, CVAR_CLIENTARCHIVE | CVAR_NOENABLEDISABLE) // Start
CVAR (chatmacro9, "I am on Xbox and can only use chat macros.", "", CVARTYPE_STRING, CVAR_CLIENTARCHIVE | CVAR_NOENABLEDISABLE) // Back
CVAR (chatmacro9, "I am on a game console and can only use chat macros.", "", CVARTYPE_STRING, CVAR_CLIENTARCHIVE | CVAR_NOENABLEDISABLE) // Back
#else
// GhostlyDeath <November 2, 2008> -- someone had the order wrong (0-9!)
CVAR (chatmacro1, "I'm ready to kick butt!", "", CVARTYPE_STRING, CVAR_CLIENTARCHIVE | CVAR_NOENABLEDISABLE)
@ -640,6 +643,8 @@ CVAR_RANGE( snd_voxtype, "2", "Voice announcer type",
CVAR( snd_gamesfx, "1", "Game SFX", CVARTYPE_BOOL, CVAR_CLIENTARCHIVE)
CVAR( snd_votesfx, "1", "Enable vote UI sounds", CVARTYPE_BOOL, CVAR_CLIENTARCHIVE)
CVAR( snd_crossover, "0", "Stereo switch", CVARTYPE_BOOL, CVAR_CLIENTARCHIVE)
CVAR_RANGE_FUNC_DECL(snd_samplerate, "44100", "Audio samplerate",
@ -678,7 +683,7 @@ static char *C_GetDefaultMusicSystem()
defaultmusicsystem = MS_AUDIOUNIT;
#endif
#if defined _WIN32 && !defined _XBOX
#if defined _WIN32
defaultmusicsystem = MS_PORTMIDI;
#endif
@ -739,6 +744,12 @@ CVAR( r_flashhom, "0", "Draws flashing colors where there is HOM",
CVAR( r_drawflat, "0", "Disables all texturing of walls, floors and ceilings",
CVARTYPE_BOOL, CVAR_NULL)
CVAR( r_clipmaskedspecial, "1", "Vertically clip masked midtextures when surrounding sectors have differing specials (mimics Hexen and DSDA-Doom behavior)",
CVARTYPE_BOOL, CVAR_NULL)
CVAR( r_thingsectorlight, "0", "MObjs are lit according to the average of the transfered light levels (mimics MBF behavior)",
CVARTYPE_BOOL, CVAR_NULL)
#if 0
CVAR( r_drawhitboxes, "0", "Draws a box outlining every actor's hitboxes",
CVARTYPE_BOOL, CVAR_NULL)
@ -771,13 +782,8 @@ CVAR_FUNC_DECL( r_forceteamcolor, "0", "Changes the color of all teammates to th
CVAR_FUNC_DECL( r_teamcolor, "40 cf 00", "",
CVARTYPE_STRING, CVAR_CLIENTARCHIVE | CVAR_NOENABLEDISABLE)
#ifdef _XBOX // The burn wipe works better in 720p
CVAR_RANGE( r_wipetype, "2", "",
CVARTYPE_BYTE, CVAR_CLIENTARCHIVE | CVAR_NOENABLEDISABLE, 0.0f, 3.0f)
#else
CVAR_RANGE( r_wipetype, "1", "",
CVARTYPE_BYTE, CVAR_CLIENTARCHIVE | CVAR_NOENABLEDISABLE, 0.0f, 3.0f)
#endif
CVAR_RANGE( r_showendoom, "0", "Display the ENDDOOM text after quitting",
CVARTYPE_BYTE, CVAR_CLIENTARCHIVE | CVAR_NOENABLEDISABLE, 0.0f, 2.0f) // [ML] 1/5/10: Add endoom support

View file

@ -158,7 +158,7 @@ void NetDemo::cleanUp()
void NetDemo::error(const std::string &message)
{
cleanUp();
Printf(PRINT_HIGH, "%s\n", message);
PrintFmt(PRINT_HIGH, "{}\n", message);
}
/**
@ -175,7 +175,7 @@ void NetDemo::fatalError(const std::string &message)
gameaction = ga_nothing;
gamestate = GS_FULLCONSOLE;
Printf(PRINT_HIGH, "%s\n", message);
PrintFmt(PRINT_HIGH, "{}\n", message);
}
//
@ -455,7 +455,7 @@ bool NetDemo::startRecording(const std::string &filename)
state = NetDemo::st_recording;
header.starting_gametic = gametic;
Printf(PRINT_HIGH, "Recording netdemo %s.\n", filename);
PrintFmt(PRINT_HIGH, "Recording netdemo {}.\n", filename);
if (connected)
{
@ -584,7 +584,7 @@ bool NetDemo::startPlaying(const std::string &filename)
fseek(demofp, NetDemo::HEADER_SIZE, SEEK_SET);
state = NetDemo::st_playing;
Printf(PRINT_HIGH, "Playing netdemo %s.\n", filename);
PrintFmt(PRINT_HIGH, "Playing netdemo {}.\n", filename);
return true;
}
@ -683,7 +683,7 @@ bool NetDemo::stopRecording()
fclose(demofp);
demofp = NULL;
Printf(PRINT_HIGH, "Demo recording has stopped.\n");
PrintFmt(PRINT_HIGH, "Demo recording has stopped.\n");
reset();
return true;
}
@ -707,7 +707,7 @@ bool NetDemo::stopPlaying()
demofp = NULL;
}
Printf(PRINT_HIGH, "Demo has ended.\n");
PrintFmt(PRINT_HIGH, "Demo has ended.\n");
reset();
gameaction = ga_fullconsole;
gamestate = GS_FULLCONSOLE;
@ -1480,7 +1480,7 @@ void NetDemo::writeSnapshotData(std::vector<byte>& buf)
arc << ACS_WorldVars[i];
ACSWorldGlobalArray worldarr = ACS_WorldArrays[i];
arc << worldarr.size();
for (const auto [key, val] : worldarr)
for (const auto& [key, val] : worldarr)
{
arc << key;
arc << val;
@ -1493,7 +1493,7 @@ void NetDemo::writeSnapshotData(std::vector<byte>& buf)
arc << ACS_GlobalVars[i];
ACSWorldGlobalArray globalarr = ACS_GlobalArrays[i];
arc << globalarr.size();
for (const auto [key, val] : globalarr)
for (const auto& [key, val] : globalarr)
{
arc << key;
arc << val;

View file

@ -96,8 +96,8 @@ static struct DownloadState
*/
void CL_DownloadInit()
{
Printf("CL_DownloadInit: Init HTTP subsystem (libcurl %d.%d.%d)\n",
LIBCURL_VERSION_MAJOR, LIBCURL_VERSION_MINOR, LIBCURL_VERSION_PATCH);
PrintFmt("CL_DownloadInit: Init HTTP subsystem (libcurl {}.{}.{})\n",
LIBCURL_VERSION_MAJOR, LIBCURL_VERSION_MINOR, LIBCURL_VERSION_PATCH);
curl_global_init(CURL_GLOBAL_ALL);
@ -142,7 +142,7 @@ bool CL_StartDownload(const Websites& urls, const OWantFile& filename, unsigned
{
if (::dlstate.state != STATE_READY)
{
Printf(PRINT_WARNING, "Can't start download when download state is not ready.\n");
PrintFmt(PRINT_WARNING, "Can't start download when download state is not ready.\n");
return false;
}
@ -170,24 +170,24 @@ bool CL_StartDownload(const Websites& urls, const OWantFile& filename, unsigned
if (checkurls.empty())
{
Printf(PRINT_WARNING, "No sites were provided for download.\n");
PrintFmt(PRINT_WARNING, "No sites were provided for download.\n");
return false;
}
if (W_IsFilenameCommercialWAD(filename.getBasename()))
{
Printf(PRINT_WARNING, "%s is a commercial WAD file and cannot be downloaded by Odamex.\n"
"A copy can be obtained through purchasing DOOM + DOOM II from Steam or GOG.\n",
filename.getBasename());
PrintFmt(PRINT_WARNING, "{} is a commercial WAD file and cannot be downloaded by Odamex.\n"
"A copy can be obtained through purchasing DOOM + DOOM II from Steam or GOG.\n",
filename.getBasename());
return false;
}
if (W_IsFilehashCommercialWAD(filename.getWantedMD5()))
{
const fileIdentifier_t* id = W_GameInfo(filename.getWantedMD5());
Printf(PRINT_WARNING, "%s is a renamed commercial wad file containing %s.\n"
"A copy of %s can be obtained through purchasing DOOM + DOOM II from Steam or GOG.\n",
filename.getBasename(), id->mNiceName, id->mFilename);
PrintFmt(PRINT_WARNING, "{} is a renamed commercial wad file containing {}.\n"
"A copy of {} can be obtained through purchasing DOOM + DOOM II from Steam or GOG.\n",
filename.getBasename(), id->mNiceName, id->mFilename);
return false;
}
@ -229,7 +229,7 @@ static void CheckDone(const OTransferInfo& info)
::dlstate.state = STATE_DOWNLOADING;
::dlstate.url = info.url;
Printf("Found file at %s.\n", info.url);
PrintFmt("Found file at {}.\n", info.url);
}
/**
@ -248,9 +248,9 @@ static void CheckError(const char* msg)
// Three strikes and you're out.
if (::dlstate.checkfails >= 3)
{
Printf(PRINT_WARNING, "Could not find %s at %s (%s)...\n",
::dlstate.checkfilename,
::dlstate.checkurls.at(::dlstate.checkurlidx), msg);
PrintFmt(PRINT_WARNING, "Could not find {} at {} ({})...\n",
::dlstate.checkfilename,
::dlstate.checkurls.at(::dlstate.checkurlidx), msg);
// Check the next base URL.
::dlstate.checkfails = 0;
@ -258,8 +258,8 @@ static void CheckError(const char* msg)
if (::dlstate.checkurlidx >= ::dlstate.checkurls.size())
{
// No more base URL's to check - our luck has run out.
Printf(PRINT_WARNING, "Download failed, no sites have %s for download.\n",
::dlstate.checkfilename);
PrintFmt(PRINT_WARNING, "Download failed, no sites have {} for download.\n",
::dlstate.checkfilename);
::dlstate.Ready();
}
}
@ -303,7 +303,7 @@ static void TickCheck()
}
::dlstate.state = STATE_CHECKING;
Printf("Checking for file at %s...\n", fullurl);
PrintFmt("Checking for file at {}...\n", fullurl);
}
// Tick the checker - the done/error callbacks mutate the state appropriately,
@ -350,7 +350,7 @@ static void TransferDone(const OTransferInfo& info)
{
std::string bytes;
StrFormatBytes(bytes, info.speed);
Printf("Download completed at %s/s.\n", bytes);
PrintFmt("Download completed at {}/s.\n", bytes);
if (::dlstate.flags & DL_RECONNECT)
CL_Reconnect();
@ -358,7 +358,7 @@ static void TransferDone(const OTransferInfo& info)
static void TransferError(const char* msg)
{
Printf(PRINT_WARNING, "Download error (%s).\n", msg);
PrintFmt(PRINT_WARNING, "Download error ({}).\n", msg);
}
static void TickDownload()
@ -392,7 +392,7 @@ static void TickDownload()
break;
// Otherwise, set the destination to the empty string and try again.
Printf(PRINT_WARNING, "Could not save to %s (%s)\n", dest, strerror(err));
PrintFmt(PRINT_WARNING, "Could not save to {} ({})\n", dest, strerror(err));
dest = "";
}
@ -415,7 +415,7 @@ static void TickDownload()
}
::dlstate.state = STATE_DOWNLOADING;
Printf("Downloading %s...\n", ::dlstate.url);
PrintFmt("Downloading {}...\n", ::dlstate.url);
}
if (!::dlstate.transfer->tick())
@ -429,8 +429,8 @@ static void TickDownload()
if (::dlstate.checkurlidx >= ::dlstate.checkurls.size())
{
// No more base URL's to check - our luck has run out.
Printf(PRINT_WARNING, "Download failed, no sites have %s for download.\n",
::dlstate.checkfilename);
PrintFmt(PRINT_WARNING, "Download failed, no sites have {} for download.\n",
::dlstate.checkfilename);
::dlstate.Ready();
}
}
@ -505,12 +505,12 @@ EXTERN_CVAR(cl_downloadsites)
static void DownloadHelp()
{
Printf("download - Downloads a WAD file\n\n"
"Usage:\n"
" ] download get <FILENAME>\n"
" Downloads the file FILENAME from your configured download sites.\n"
" ] download stop\n"
" Stop an in-progress download.");
PrintFmt("download - Downloads a WAD file\n\n"
"Usage:\n"
" ] download get <FILENAME>\n"
" Downloads the file FILENAME from your configured download sites.\n"
" ] download stop\n"
" Stop an in-progress download.");
}
BEGIN_COMMAND(download)
@ -538,7 +538,7 @@ BEGIN_COMMAND(download)
if (stricmp(argv[1], "stop") == 0)
{
if (CL_StopDownload())
Printf(PRINT_WARNING, "Download cancelled.\n");
PrintFmt(PRINT_WARNING, "Download cancelled.\n");
return;
}

View file

@ -65,10 +65,7 @@
#include "g_spawninv.h"
#include "g_gametype.h"
#include "p_horde.h"
#ifdef _XBOX
#include "i_xbox.h"
#endif
#include "g_musinfo.h"
#include <math.h> // for pow()
@ -183,6 +180,13 @@ CVAR_FUNC_IMPL(cl_mouselook)
R_InitSkyMap ();
}
CVAR_FUNC_IMPL(joy_freelook)
{
// [RV] - Center view, Update Skies
AddCommandString("centerview");
R_InitSkyMap();
}
char demoname[256];
extern bool simulated_connection;
@ -290,8 +294,8 @@ BEGIN_COMMAND (turnspeeds)
{
if (argc == 1)
{
Printf (PRINT_HIGH, "Current turn speeds: %d %d %d\n",
angleturn[0], angleturn[1], angleturn[2]);
PrintFmt(PRINT_HIGH, "Current turn speeds: {} {} {}\n",
angleturn[0], angleturn[1], angleturn[2]);
}
else
{
@ -335,8 +339,8 @@ BEGIN_COMMAND (togglerun)
{
cl_run.Set(!cl_run.value());
Printf(PRINT_HIGH, "Always run %s\n",
cl_run.value() ? "on" : "off");
PrintFmt(PRINT_HIGH, "Always run {}\n",
cl_run.value() ? "on" : "off");
}
END_COMMAND (togglerun)
@ -826,7 +830,7 @@ int outrate;
BEGIN_COMMAND(netstat)
{
Printf (PRINT_HIGH, "in = %d out = %d \n", netin, netout);
PrintFmt(PRINT_HIGH, "in = {} out = {} \n", netin, netout);
}
END_COMMAND(netstat)
@ -1058,8 +1062,8 @@ void G_Ticker (void)
MSG_WriteMarker(&net_buffer, clc_disconnect);
NET_SendPacket(net_buffer, serveraddr);
Printf(PRINT_WARNING,
"Got unknown challenge %d while connecting, disconnecting.\n", type);
PrintFmt(PRINT_WARNING,
"Got unknown challenge {} while connecting, disconnecting.\n", type);
}
}
}
@ -1557,7 +1561,7 @@ void G_DoLoadGame (void)
FILE *stdfile = fopen (savename.c_str(), "rb");
if (stdfile == NULL)
{
Printf (PRINT_HIGH, "Could not read savegame '%s'\n", savename);
PrintFmt(PRINT_HIGH, "Could not read savegame '{}'\n", savename);
return;
}
@ -1565,13 +1569,13 @@ void G_DoLoadGame (void)
size_t readlen = fread (text, 16, 1, stdfile);
if (readlen < 1)
{
Printf (PRINT_HIGH, "Failed to read savegame '%s'\n", savename);
PrintFmt(PRINT_HIGH, "Failed to read savegame '{}'\n", savename);
fclose(stdfile);
return;
}
if (strncmp (text, SAVESIG, 16))
{
Printf (PRINT_HIGH, "Savegame '%s' is from a different version\n", savename);
PrintFmt(PRINT_HIGH, "Savegame '{}' is from a different version\n", savename);
fclose(stdfile);
@ -1580,7 +1584,7 @@ void G_DoLoadGame (void)
readlen = fread (text, 8, 1, stdfile);
if (readlen < 1)
{
Printf (PRINT_HIGH, "Failed to read savegame '%s'\n", savename);
PrintFmt(PRINT_HIGH, "Failed to read savegame '{}'\n", savename);
fclose(stdfile);
return;
}
@ -1591,9 +1595,9 @@ void G_DoLoadGame (void)
FLZOFile savefile (stdfile, FFile::EReading);
if (!savefile.IsOpen ())
I_Error ("Savegame '{}' is corrupt\n", savename);
I_Error("Savegame '{}' is corrupt\n", savename);
Printf (PRINT_HIGH, "Loading savegame '%s'...\n", savename);
PrintFmt(PRINT_HIGH, "Loading savegame '{}'...\n", savename);
CL_QuitNetGame(NQ_SILENT);
@ -1625,6 +1629,7 @@ void G_DoLoadGame (void)
arc >> level.time;
P_SerializeMusInfo(arc);
for (i = 0; i < NUM_WORLDVARS; i++)
{
@ -1683,11 +1688,7 @@ void G_SaveGame (int slot, std::string_view description)
*/
void G_BuildSaveName(std::string &name, int slot)
{
#ifdef _XBOX
std::string path = xbox_GetSavePath(name, slot);
#else
std::string path = M_GetUserFileName(name);
#endif
name = fmt::sprintf("%s" PATHSEP "odasv%d.ods", path, slot);
}
@ -1707,11 +1708,7 @@ void G_DoSaveGame()
return;
}
#ifdef _XBOX
xbox_WriteSaveMeta(name.substr(0, name.rfind(PATHSEPCHAR)), description.c_str());
#endif
Printf (PRINT_HIGH, "Saving game to '%s'...\n", name);
PrintFmt(PRINT_HIGH, "Saving game to '{}'...\n", name);
fwrite (description.c_str(), SAVESTRINGSIZE, 1, stdfile);
fwrite (SAVESIG, 16, 1, stdfile);
@ -1735,13 +1732,14 @@ void G_DoSaveGame()
P_SerializeHorde(arc);
arc << level.time;
P_SerializeMusInfo(arc);
for (int i = 0; i < NUM_WORLDVARS; i++)
{
arc << ACS_WorldVars[i];
ACSWorldGlobalArray worldarr = ACS_WorldArrays[i];
arc << worldarr.size();
for (const auto [key, val] : worldarr)
for (const auto& [key, val] : worldarr)
{
arc << key;
arc << val;
@ -1753,20 +1751,19 @@ void G_DoSaveGame()
arc << ACS_GlobalVars[i];
ACSWorldGlobalArray globalarr = ACS_GlobalArrays[i];
arc << globalarr.size();
for (const auto [key, val] : globalarr)
for (const auto& [key, val] : globalarr)
{
arc << key;
arc << val;
}
}
arc << (BYTE)0x1d; // consistancy marker
gameaction = ga_nothing;
savedescription[0] = 0;
Printf (PRINT_HIGH, "%s\n", GStrings(GGSAVED));
PrintFmt(PRINT_HIGH, "{}\n", GStrings(GGSAVED));
arc.Close ();
if (level.info->snapshot != NULL)
@ -1850,12 +1847,12 @@ BEGIN_COMMAND(playdemo)
}
else
{
Printf(PRINT_WARNING, "Cannot play demo because WAD didn't load\n");
Printf(PRINT_WARNING, "Use the 'wad' command\n");
PrintFmt(PRINT_WARNING, "Cannot play demo because WAD didn't load\n");
PrintFmt(PRINT_WARNING, "Use the 'wad' command\n");
}
}
else
Printf(PRINT_HIGH, "Usage: playdemo lumpname or file\n");
PrintFmt(PRINT_HIGH, "Usage: playdemo lumpname or file\n");
}
END_COMMAND(playdemo)
@ -1868,7 +1865,7 @@ BEGIN_COMMAND(streamdemo)
}
else
{
Printf(PRINT_HIGH, "Usage: streamdemo lumpname or file\n");
PrintFmt(PRINT_HIGH, "Usage: streamdemo lumpname or file\n");
}
}
END_COMMAND(streamdemo)
@ -1904,7 +1901,7 @@ void G_DoPlayDemo(bool justStreamInput)
std::string found = M_FindUserFileName(::defdemoname, ".lmp");
if (found.empty())
{
Printf(PRINT_WARNING, "Could not find demo %s\n", ::defdemoname);
PrintFmt(PRINT_WARNING, "Could not find demo {}\n", ::defdemoname);
gameaction = ga_fullconsole;
return;
}
@ -1921,7 +1918,7 @@ void G_DoPlayDemo(bool justStreamInput)
if (bytelen)
Z_Free(demobuffer);
Printf(PRINT_WARNING, "DOOM Demo file too short\n");
PrintFmt(PRINT_WARNING, "DOOM Demo file too short\n");
gameaction = ga_fullconsole;
return;
}
@ -1935,7 +1932,7 @@ void G_DoPlayDemo(bool justStreamInput)
demo_p[0] == DOOM_1_9p_DEMO ||
demo_p[0] == DOOM_1_9_1_DEMO)
{
Printf(PRINT_HIGH, "Playing DOOM demo %s\n", defdemoname);
PrintFmt(PRINT_HIGH, "Playing DOOM demo {}\n", defdemoname);
demostartgametic = gametic;
demoversion = *demo_p++ == DOOM_1_9_1_DEMO ? LMP_DOOM_1_9_1 : LMP_DOOM_1_9;
@ -1976,7 +1973,7 @@ void G_DoPlayDemo(bool justStreamInput)
if (!validplayer(con))
{
Z_Free(demobuffer);
Printf(PRINT_HIGH, "DOOM Demo: invalid console player %d of %lu\n", who + 1, players.size());
PrintFmt(PRINT_HIGH, "DOOM Demo: invalid console player {} of {}\n", who + 1, players.size());
gameaction = ga_fullconsole;
return;
}
@ -2048,7 +2045,7 @@ void G_DoPlayDemo(bool justStreamInput)
}
else
{
Printf(PRINT_WARNING, "Unsupported demo format. If you are trying to play an Odamex " \
PrintFmt(PRINT_WARNING, "Unsupported demo format. If you are trying to play an Odamex " \
"netdemo, please use the netplay command\n");
gameaction = ga_nothing;
}
@ -2129,9 +2126,13 @@ bool G_CheckDemoStatus (void)
AActor *mo = idplayer(1).mo;
if (mo)
Printf(PRINT_HIGH, "demotest:%x %x %x %x\n", mo->angle, mo->x, mo->y, mo->z);
PrintFmt(PRINT_HIGH, "demotest:{:x} {:x} {:x} {:x}\n",
static_cast<uint32_t>(mo->angle),
static_cast<uint32_t>(mo->x),
static_cast<uint32_t>(mo->y),
static_cast<uint32_t>(mo->z));
else
Printf(PRINT_WARNING, "demotest:no player\n");
PrintFmt(PRINT_WARNING, "demotest:no player\n");
demotest = false;
@ -2149,15 +2150,15 @@ bool G_CheckDemoStatus (void)
int realtics = endtime * TICRATE / 1000;
float fps = float(gametic * TICRATE) / realtics;
Printf(PRINT_HIGH, "timed %i gametics in %i realtics (%.1f fps)\n",
gametic, realtics, fps);
PrintFmt(PRINT_HIGH, "timed {} gametics in {} realtics ({:.1f} fps)\n",
gametic, realtics, fps);
// exit the application
CL_QuitCommand();
return false;
}
else
Printf (PRINT_HIGH, "Demo ended.\n");
PrintFmt(PRINT_HIGH, "Demo ended.\n");
demoplayback = false;
gameaction = ga_fullconsole;

View file

@ -113,11 +113,11 @@ BEGIN_COMMAND (wad) // denis - changes wads
// [Russell] print out some useful info
if (argc == 1)
{
Printf(PRINT_HIGH, "Usage: wad pwad [...] [deh/bex [...]]\n");
Printf(PRINT_HIGH, " wad iwad [pwad [...]] [deh/bex [...]]\n");
Printf(PRINT_HIGH, "\n");
Printf(PRINT_HIGH, "Load a wad file on the fly, pwads/dehs/bexs require extension\n");
Printf(PRINT_HIGH, "eg: wad doom\n");
PrintFmt(PRINT_HIGH, "Usage: wad pwad [...] [deh/bex [...]]\n");
PrintFmt(PRINT_HIGH, " wad iwad [pwad [...]] [deh/bex [...]]\n");
PrintFmt(PRINT_HIGH, "\n");
PrintFmt(PRINT_HIGH, "Load a wad file on the fly, pwads/dehs/bexs require extension\n");
PrintFmt(PRINT_HIGH, "eg: wad doom\n");
return;
}
@ -179,8 +179,6 @@ void G_DoNewGame (void)
void G_InitNew (const char *mapname)
{
size_t i;
// [RH] Remove all particles
R_ClearParticles ();
@ -230,38 +228,38 @@ void G_InitNew (const char *mapname)
{
if (wantFast)
{
for (i = 0; i < NUMSTATES; i++)
for (auto& [_, state] : states)
{
if (states[i].flags & STATEF_SKILL5FAST &&
(states[i].tics != 1 || demoplayback))
states[i].tics >>= 1; // don't change 1->0 since it causes cycles
if (state.flags & STATEF_SKILL5FAST &&
(state.tics != 1 || demoplayback))
state.tics >>= 1; // don't change 1->0 since it causes cycles
}
for (i = 0; i < NUMMOBJTYPES; ++i)
for (auto& [_, minfo] : mobjinfo)
{
if (mobjinfo[i].altspeed != NO_ALTSPEED)
if (minfo.altspeed != NO_ALTSPEED)
{
int swap = mobjinfo[i].speed;
mobjinfo[i].speed = mobjinfo[i].altspeed;
mobjinfo[i].altspeed = swap;
int swap = minfo.speed;
minfo.speed = minfo.altspeed;
minfo.altspeed = swap;
}
}
}
else
{
for (i = 0; i < NUMSTATES; i++)
for (auto& [_, state] : states)
{
if (states[i].flags & STATEF_SKILL5FAST)
states[i].tics <<= 1; // don't change 1->0 since it causes cycles
if (state.flags & STATEF_SKILL5FAST)
state.tics <<= 1; // don't change 1->0 since it causes cycles
}
for (i = 0; i < NUMMOBJTYPES; ++i)
for (auto& [_, minfo] : mobjinfo)
{
if (mobjinfo[i].altspeed != NO_ALTSPEED)
if (minfo.altspeed != NO_ALTSPEED)
{
int swap = mobjinfo[i].altspeed;
mobjinfo[i].altspeed = mobjinfo[i].speed;
mobjinfo[i].speed = swap;
int swap = minfo.altspeed;
minfo.altspeed = minfo.speed;
minfo.speed = swap;
}
}
}
@ -774,7 +772,7 @@ void G_WorldDone()
clusters.findByCluster(levels.findByName(::level.secretmap).cluster) :
clusters.findByCluster(levels.findByName(::level.nextmap).cluster);
if (nextcluster.cluster != level.cluster && sv_gametype == GM_COOP) {
if (nextcluster.cluster != level.cluster && sv_gametype == GM_COOP && options.text != "-") {
// Only start the finale if the next level's cluster is different
// than the current one and we're not in deathmatch.
if (!nextcluster.entertext.empty())

View file

@ -70,16 +70,11 @@
#include "cl_replay.h"
#include <bitset>
#include <map>
#include <set>
#include <sstream>
#include "server.pb.h"
#ifdef _XBOX
#include "i_xbox.h"
#endif
#if _MSC_VER == 1310
#pragma optimize("",off)
#endif
@ -125,9 +120,6 @@ static int packetseq[256];
// denis - unique session key provided by the server
std::string digest;
// denis - clientside compressor, used for decompression
huffman_client compressor;
std::string server_host = ""; // hostname of server
// [SL] 2011-06-27 - Class to record and playback network recordings
@ -301,8 +293,8 @@ void M_Ticker(void);
size_t P_NumPlayersInGame();
void G_PlayerReborn (player_t &player);
void P_KillMobj (AActor *source, AActor *target, AActor *inflictor, bool joinkill);
void P_SetPsprite (player_t *player, int position, statenum_t stnum);
void P_KillMobj (AActor *source, AActor *target, const AActor *inflictor, bool joinkill);
void P_SetPsprite (player_t *player, int position, int32_t stnum);
void P_ExplodeMissile (AActor* mo);
void P_CalcHeight (player_t *player);
bool P_CheckMissileSpawn (AActor* th);
@ -363,7 +355,7 @@ void CL_ResyncWorldIndex()
void Host_EndGame(const char *msg)
{
Printf("%s", msg);
PrintFmt("{}", msg);
CL_QuitNetGame(NQ_SILENT);
}
@ -436,18 +428,18 @@ void CL_QuitNetGame2(const netQuitReason_e reason, const char* file, const int l
default: // Also NQ_SILENT
break;
case NQ_DISCONNECT:
Printf("Disconnected from server\n");
PrintFmt("Disconnected from server\n");
break;
case NQ_ABORT:
Printf("Connection attempt aborted\n");
PrintFmt("Connection attempt aborted\n");
break;
case NQ_PROTO:
Printf("Disconnected from server: Unrecoverable protocol error\n");
PrintFmt("Disconnected from server: Unrecoverable protocol error\n");
break;
}
if (::debug_disconnect)
Printf(" (%s:%d)\n", file, line);
PrintFmt(" ({}:{})\n", file, line);
}
@ -593,6 +585,8 @@ void CL_SpyCycle(Iterator begin, Iterator end)
ST_ForceRefresh();
}
P_FriendlyEffects(); // Mark any new friendly monsters with an effect
return;
}
} while (it != sentinal);
@ -683,10 +677,10 @@ void CL_RunTics()
// debugging output
extern unsigned char prndindex;
if (!(players.empty()) && players.begin()->mo)
Printf("level.time %d, prndindex %d, %d %d %d\n",
level.time, prndindex, players.begin()->mo->x, players.begin()->mo->y, players.begin()->mo->z);
PrintFmt("level.time {}, prndindex {}, {} {} {}\n",
level.time, prndindex, players.begin()->mo->x, players.begin()->mo->y, players.begin()->mo->z);
else
Printf("level.time %d, prndindex %d\n", level.time, prndindex);
PrintFmt("level.time %d, prndindex %d\n", level.time, prndindex);
}
}
else
@ -722,12 +716,12 @@ BEGIN_COMMAND (connect)
{
if (argc == 1)
{
Printf("Usage: connect ip[:port] [password]\n");
Printf("\n");
Printf("Connect to a server, with optional port number");
Printf(" and/or password\n");
Printf("eg: connect 127.0.0.1\n");
Printf("eg: connect 192.168.0.1:12345 secretpass\n");
PrintFmt("Usage: connect ip[:port] [password]\n");
PrintFmt("\n");
PrintFmt("Connect to a server, with optional port number");
PrintFmt(" and/or password\n");
PrintFmt("eg: connect 127.0.0.1\n");
PrintFmt("eg: connect 192.168.0.1:12345 secretpass\n");
return;
}
@ -762,7 +756,7 @@ BEGIN_COMMAND (connect)
}
else
{
Printf("Could not resolve host %s\n", target);
PrintFmt("Could not resolve host {}\n", target);
memset(&serveraddr, 0, sizeof(serveraddr));
}
}
@ -796,11 +790,11 @@ BEGIN_COMMAND (players)
}
// Print them, ordered by player id.
Printf("PLAYERS IN GAME:\n");
PrintFmt("PLAYERS IN GAME:\n");
for (const auto& [id, name] : mplayers) {
Printf("%3d. %s\n", id, name);
PrintFmt("{:>3d}. {}\n", id, name);
}
Printf("%lu %s\n", mplayers.size(), mplayers.size() == 1 ? "PLAYER" : "PLAYERS");
PrintFmt("{} {}\n", mplayers.size(), mplayers.size() == 1 ? "PLAYER" : "PLAYERS");
}
END_COMMAND (players)
@ -854,7 +848,7 @@ BEGIN_COMMAND (kill)
if (sv_allowcheats || G_IsCoopGame())
MSG_WriteMarker(&net_buffer, clc_kill);
else
Printf ("You must run the server with '+set sv_allowcheats 1' or disable sv_keepkeys to enable this command.\n");
PrintFmt("You must run the server with '+set sv_allowcheats 1' or disable sv_keepkeys to enable this command.\n");
}
END_COMMAND (kill)
@ -887,7 +881,7 @@ BEGIN_COMMAND (serverinfo)
std::sort(server_cvars.begin(), server_cvars.end());
// Heading
Printf ("\n%*s - Value\n", static_cast<int>(MaxFieldLength), "Name");
PrintFmt("\n{1:>{0}} - Value\n", MaxFieldLength, "Name");
// Data
for (const auto& varname : server_cvars)
@ -895,13 +889,13 @@ BEGIN_COMMAND (serverinfo)
cvar_t *dummy;
Cvar = cvar_t::FindCVar(varname.c_str(), &dummy);
Printf( "%*s - %s\n",
static_cast<int>(MaxFieldLength),
Cvar->name(),
Cvar->str());
PrintFmt("{1:>{0}} - {2}\n",
MaxFieldLength,
Cvar->name(),
Cvar->str());
}
Printf ("\n");
PrintFmt("\n");
}
END_COMMAND (serverinfo)
@ -954,16 +948,16 @@ END_COMMAND (rcon_logout)
BEGIN_COMMAND (playerteam)
{
if (G_IsTeamGame())
Printf("Your are in the %s team.\n", V_GetTeamColor(consoleplayer().userinfo.team));
PrintFmt("Your are in the {} team.\n", V_GetTeamColor(consoleplayer().userinfo.team));
else
Printf("You need to play a team-based gamemode in order to use this command.\n");
PrintFmt("You need to play a team-based gamemode in order to use this command.\n");
}
END_COMMAND (playerteam)
BEGIN_COMMAND (changeteams)
{
int iTeam = (int)consoleplayer().userinfo.team;
iTeam = ++iTeam % sv_teamsinplay.asInt();
iTeam = (iTeam + 1) % sv_teamsinplay.asInt();
cl_team.Set(GetTeamInfo((team_t)iTeam)->ColorStringUpper.c_str());
}
END_COMMAND (changeteams)
@ -998,17 +992,17 @@ END_COMMAND(ready)
static void NetCmdHelp()
{
Printf(PRINT_HIGH,
"netcmd - Send an arbitrary string command to a server\n\n"
"Common commands:\n"
" ] netcmd help\n"
" Check to see if the server has any server-specific netcmd's.\n\n"
" ] netcmd motd\n"
" Ask the server for the MOTD.\n\n"
" ] netcmd ready\n"
" Set yourself as ready or unready.\n\n"
" ] netcmd vote <\"yes\"|\"no\">\n"
" Vote \"yes\" or \"no\" in an ongoing vote.\n");
PrintFmt(PRINT_HIGH,
"netcmd - Send an arbitrary string command to a server\n\n"
"Common commands:\n"
" ] netcmd help\n"
" Check to see if the server has any server-specific netcmd's.\n\n"
" ] netcmd motd\n"
" Ask the server for the MOTD.\n\n"
" ] netcmd ready\n"
" Set yourself as ready or unready.\n\n"
" ] netcmd vote <\"yes\"|\"no\">\n"
" Vote \"yes\" or \"no\" in an ongoing vote.\n");
}
BEGIN_COMMAND(netcmd)
@ -1080,12 +1074,12 @@ BEGIN_COMMAND (spy)
{
if (argc <= 1) {
if (spyplayername.length() > 0) {
Printf(PRINT_HIGH, "Unfollowing player '%s'.\n", spyplayername);
PrintFmt(PRINT_HIGH, "Unfollowing player '{}'.\n", spyplayername);
// revert to not spying:
displayplayer_id = consoleplayer_id;
} else {
Printf(PRINT_HIGH, "Expecting player name. Try 'players' to list all player names.\n");
PrintFmt(PRINT_HIGH, "Expecting player name. Try 'players' to list all player names.\n");
}
// clear last player name:
@ -1094,8 +1088,8 @@ BEGIN_COMMAND (spy)
// remember player name in case of disconnect/reconnect e.g. level change:
spyplayername = argv[1];
Printf(PRINT_HIGH, "Following player '%s'. Use 'spy' with no player name to unfollow.\n",
spyplayername);
PrintFmt(PRINT_HIGH, "Following player '{}'. Use 'spy' with no player name to unfollow.\n",
spyplayername);
}
CL_CheckDisplayPlayer();
@ -1164,7 +1158,7 @@ void CL_NetDemoPlay(const std::string& filename)
found = M_GetNetDemoFileName(filename, cl_netdemodir);
if (found.empty())
{
Printf(PRINT_WARNING, "Could not find demo %s.\n", filename);
PrintFmt(PRINT_WARNING, "Could not find demo {}.\n", filename);
return;
}
}
@ -1189,14 +1183,14 @@ BEGIN_COMMAND(netrecord)
{
if (netdemo.isRecording())
{
Printf(PRINT_HIGH, "Already recording a netdemo. Please stop recording before "\
"beginning a new netdemo recording.\n");
PrintFmt(PRINT_HIGH, "Already recording a netdemo. Please stop recording before "\
"beginning a new netdemo recording.\n");
return;
}
if (!connected || simulated_connection)
{
Printf(PRINT_HIGH, "You must be connected to a server to record a netdemo.\n");
PrintFmt(PRINT_HIGH, "You must be connected to a server to record a netdemo.\n");
return;
}
@ -1217,13 +1211,13 @@ BEGIN_COMMAND(netpause)
{
netdemo.resume();
paused = false;
Printf(PRINT_HIGH, "Demo resumed.\n");
PrintFmt(PRINT_HIGH, "Demo resumed.\n");
}
else if (netdemo.isPlaying())
{
netdemo.pause();
paused = true;
Printf(PRINT_HIGH, "Demo paused.\n");
PrintFmt(PRINT_HIGH, "Demo paused.\n");
}
}
END_COMMAND(netpause)
@ -1232,7 +1226,7 @@ BEGIN_COMMAND(netplay)
{
if(argc <= 1)
{
Printf(PRINT_HIGH, "Usage: netplay <demoname>\n");
PrintFmt(PRINT_HIGH, "Usage: netplay <demoname>\n");
return;
}
@ -1258,15 +1252,15 @@ BEGIN_COMMAND(netdemostats)
int curtime = netdemo.calculateTimeElapsed();
int totaltime = netdemo.calculateTotalTime();
Printf(PRINT_HIGH, "\n%s\n", netdemo.getFileName());
Printf(PRINT_HIGH, "============================================\n");
Printf(PRINT_HIGH, "Total time: %i seconds\n", totaltime);
Printf(PRINT_HIGH, "Current position: %i seconds (%i%%)\n",
PrintFmt(PRINT_HIGH, "\n{}\n", netdemo.getFileName());
PrintFmt(PRINT_HIGH, "============================================\n");
PrintFmt(PRINT_HIGH, "Total time: {} seconds\n", totaltime);
PrintFmt(PRINT_HIGH, "Current position: {} seconds ({}%)\n",
curtime, curtime * 100 / totaltime);
Printf(PRINT_HIGH, "Number of maps: %lu\n", maptimes.size());
PrintFmt(PRINT_HIGH, "Number of maps: {}\n", maptimes.size());
for (size_t i = 0; i < maptimes.size(); i++)
{
Printf(PRINT_HIGH, "> %02lu Starting time: %i seconds\n",
PrintFmt(PRINT_HIGH, "> {:02d} Starting time: {} seconds\n",
i + 1, maptimes[i]);
}
}
@ -1414,6 +1408,8 @@ void CL_SpectatePlayer(player_t& player, bool spectate)
{
R_ForceViewWindowResize(); // toggline spectator mode affects status bar visibility
P_FriendlyEffects(); // Mark any new friendly monsters with an effect
if (player.spectator)
{
player.playerstate = PST_LIVE; // Resurrect dead spectators
@ -1460,7 +1456,7 @@ void CL_RequestConnectInfo(void)
{
connecttimeout = 140;
Printf(PRINT_HIGH, "Connecting to %s...\n", NET_AdrToString(serveraddr));
PrintFmt(PRINT_HIGH, "Connecting to {}...\n", NET_AdrToString(serveraddr));
SZ_Clear(&net_buffer);
MSG_WriteLong(&net_buffer, LAUNCHER_CHALLENGE);
@ -1483,9 +1479,9 @@ void CL_QuitAndTryDownload(const OWantFile& missing_file)
if (missing_file.getBasename().empty())
{
Printf(PRINT_WARNING,
"Tried to download an empty file. This is probably a bug "
"in the client where an empty file is considered missing.\n");
PrintFmt(PRINT_WARNING,
"Tried to download an empty file. This is probably a bug "
"in the client where an empty file is considered missing.\n");
CL_QuitNetGame(NQ_DISCONNECT);
return;
}
@ -1493,10 +1489,10 @@ void CL_QuitAndTryDownload(const OWantFile& missing_file)
if (!cl_serverdownload)
{
// Downloading is disabled client-side
Printf(PRINT_WARNING,
"Unable to find \"%s\". Downloading is disabled on your client. Go to "
"Options > Network Options to enable downloading.\n",
missing_file.getBasename());
PrintFmt(PRINT_WARNING,
"Unable to find \"{}\". Downloading is disabled on your client. Go to "
"Options > Network Options to enable downloading.\n",
missing_file.getBasename());
CL_QuitNetGame(NQ_DISCONNECT);
return;
}
@ -1504,9 +1500,9 @@ void CL_QuitAndTryDownload(const OWantFile& missing_file)
if (netdemo.isPlaying())
{
// Playing a netdemo and unable to download from the server
Printf(PRINT_WARNING,
"Unable to find \"%s\". Cannot download while playing a netdemo.\n",
missing_file.getBasename());
PrintFmt(PRINT_WARNING,
"Unable to find \"{}\". Cannot download while playing a netdemo.\n",
missing_file.getBasename());
CL_QuitNetGame(NQ_DISCONNECT);
return;
}
@ -1514,9 +1510,9 @@ void CL_QuitAndTryDownload(const OWantFile& missing_file)
if (sv_downloadsites.str().empty() && cl_downloadsites.str().empty())
{
// Nobody has any download sites configured.
Printf("Unable to find \"%s\". Both your client and the server have no "
"download sites configured.\n",
missing_file.getBasename());
PrintFmt("Unable to find \"{}\". Both your client and the server have no "
"download sites configured.\n",
missing_file.getBasename());
CL_QuitNetGame(NQ_DISCONNECT);
return;
}
@ -1536,8 +1532,8 @@ void CL_QuitAndTryDownload(const OWantFile& missing_file)
downloadsites.insert(downloadsites.end(), clientsites.begin(), clientsites.end());
// Disconnect from the server before we start the download.
Printf(PRINT_HIGH, "Need to download \"%s\", disconnecting from server...\n",
missing_file.getBasename());
PrintFmt(PRINT_HIGH, "Need to download \"{}\", disconnecting from server...\n",
missing_file.getBasename());
CL_QuitNetGame(NQ_SILENT);
// Start the download.
@ -1566,8 +1562,8 @@ bool CL_PrepareConnect()
std::string server_map = MSG_ReadString();
byte server_wads = MSG_ReadByte();
Printf("Found server at %s.\n\n", NET_AdrToString(::serveraddr));
Printf("> Hostname: %s\n", server_host);
PrintFmt("Found server at {}.\n\n", NET_AdrToString(::serveraddr));
PrintFmt("> Hostname: {}\n", server_host);
std::vector<std::string> newwadnames;
newwadnames.reserve(server_wads);
@ -1599,15 +1595,15 @@ bool CL_PrepareConnect()
OMD5Hash::makeFromHexStr(hash, hashStr);
if (!OWantFile::makeWithHash(file, newwadnames.at(i), OFILE_WAD, hash))
{
Printf(PRINT_WARNING,
"Could not construct wanted file \"%s\" that server requested.\n",
newwadnames.at(i));
PrintFmt(PRINT_WARNING,
"Could not construct wanted file \"{}\" that server requested.\n",
newwadnames.at(i));
CL_QuitNetGame(NQ_ABORT);
return false;
}
Printf("> %s\n %s\n", file.getBasename(),
file.getWantedMD5().getHexStr());
PrintFmt("> {}\n {}\n", file.getBasename(),
file.getWantedMD5().getHexStr());
}
// Download website - needed for HTTP downloading to work.
@ -1627,7 +1623,7 @@ bool CL_PrepareConnect()
}
}
Printf("> Map: %s\n", server_map);
PrintFmt("> Map: {}\n", server_map);
version = MSG_ReadShort();
if(version > VERSION)
@ -1672,12 +1668,12 @@ bool CL_PrepareConnect()
int major, minor, patch;
BREAKVER(gameversion, major, minor, patch);
Printf(PRINT_HIGH, "> Server Version %i.%i.%i\n", major, minor, patch);
PrintFmt(PRINT_HIGH, "> Server Version {}.{}.{}\n", major, minor, patch);
std::string msg = VersionMessage(::gameversion, GAMEVER, NULL);
if (!msg.empty())
{
Printf(PRINT_WARNING, "%s", msg);
PrintFmt(PRINT_WARNING, "{}", msg);
CL_QuitNetGame(NQ_ABORT);
return false;
}
@ -1686,7 +1682,7 @@ bool CL_PrepareConnect()
{
// [AM] Not worth sorting out what version it actually is.
std::string msg = VersionMessage(MAKEVER(0, 3, 0), GAMEVER, NULL);
Printf(PRINT_WARNING, "%s", msg);
PrintFmt(PRINT_WARNING, "{}", msg);
CL_QuitNetGame(NQ_ABORT);
return false;
}
@ -1702,22 +1698,22 @@ bool CL_PrepareConnect()
std::string filename = MSG_ReadString();
if (!OWantFile::make(file, filename, OFILE_DEH))
{
Printf(PRINT_WARNING,
"Could not construct wanted file \"%s\" that server requested.\n",
filename);
PrintFmt(PRINT_WARNING,
"Could not construct wanted file \"{}\" that server requested.\n",
filename);
CL_QuitNetGame(NQ_ABORT);
return false;
}
Printf("> %s\n", file.getBasename());
PrintFmt("> {}\n", file.getBasename());
}
// TODO: Allow deh/bex file downloads
Printf("\n");
PrintFmt("\n");
bool ok = D_DoomWadReboot(newwadfiles, newpatchfiles);
if (!ok && missingfiles.empty())
{
Printf(PRINT_WARNING, "Could not load required set of WAD files.\n");
PrintFmt(PRINT_WARNING, "Could not load required set of WAD files.\n");
CL_QuitNetGame(NQ_ABORT);
return false;
}
@ -1725,8 +1721,8 @@ bool CL_PrepareConnect()
{
if (::missingCommercialIWAD)
{
Printf(PRINT_WARNING,
"Server requires commercial IWAD that was not found.\n");
PrintFmt(PRINT_WARNING,
"Server requires commercial IWAD that was not found.\n");
CL_QuitNetGame(NQ_ABORT);
return false;
}
@ -1767,9 +1763,7 @@ bool CL_Connect()
MSG_WriteMarker(&net_buffer, clc_ack);
MSG_WriteLong(&net_buffer, 0);
NET_SendPacket(::net_buffer, ::serveraddr);
Printf("Requesting server state...\n");
compressor.reset();
PrintFmt("Requesting server state...\n");
connected = true;
multiplayer = true;
@ -1780,7 +1774,7 @@ bool CL_Connect()
byte flags = MSG_ReadByte();
if (flags & SVF_UNUSED_MASK)
{
Printf(PRINT_WARNING, "Protocol flag bits (%u) were not understood.", flags);
PrintFmt(PRINT_WARNING, "Protocol flag bits ({}) were not understood.", flags);
CL_QuitNetGame(NQ_PROTO);
}
else if (flags & SVF_COMPRESSED)
@ -1816,7 +1810,7 @@ void CL_InitNetwork (void)
if (v)
{
localport = atoi (v);
Printf (PRINT_HIGH, "using alternate port %i\n", localport);
PrintFmt(PRINT_HIGH, "using alternate port {}\n", localport);
}
else
localport = CLIENTPORT;
@ -1863,7 +1857,7 @@ void CL_TryToConnect(DWORD server_token)
{
connecttimeout = 140; // 140 tics = 4 seconds
Printf("Joining server...\n");
PrintFmt("Joining server...\n");
SZ_Clear(&net_buffer);
MSG_WriteLong(&net_buffer, PROTO_CHALLENGE); // send challenge
@ -1969,7 +1963,7 @@ bool CL_ReadPacketHeader()
byte flags = MSG_ReadByte();
if (flags & SVF_UNUSED_MASK)
{
Printf(PRINT_WARNING, "Protocol flag bits (%u) were not understood.", flags);
PrintFmt(PRINT_WARNING, "Protocol flag bits ({}) were not understood.", flags);
CL_QuitNetGame(NQ_PROTO);
}
else if (flags & SVF_COMPRESSED)
@ -2039,7 +2033,7 @@ void CL_ParseCommands()
if (!protos.empty())
{
Printf(PRINT_WARNING, "CL_ParseCommands: %s\n", err);
PrintFmt(PRINT_WARNING, "CL_ParseCommands: {}\n", err);
for (Protos::const_iterator it = protos.begin(); it != protos.end(); ++it)
{
@ -2047,13 +2041,13 @@ void CL_ParseCommands()
ptrdiff_t idx = it - protos.begin() + 1;
std::string svc = SVCName(it->header);
size_t siz = it->size;
Printf(PRINT_WARNING, "%c %2zd [%s] %zub\n", latest, idx, svc,
siz);
PrintFmt(PRINT_WARNING, "{:c} {:>2d} [{}] {}b\n", latest, idx, svc,
siz);
}
}
else
{
Printf(PRINT_WARNING, "CL_ParseCommands: %s\n", err);
PrintFmt(PRINT_WARNING, "CL_ParseCommands: {}\n", err);
}
CL_QuitNetGame(NQ_PROTO);
@ -2062,8 +2056,8 @@ void CL_ParseCommands()
// Measure length of each message, so we can keep track of bandwidth.
if (::net_message.BytesRead() < byteStart)
{
Printf("CL_ParseCommands: end byte (%lu) < start byte (%lu)\n",
::net_message.BytesRead(), byteStart);
PrintFmt("CL_ParseCommands: end byte ({}) < start byte ({})\n",
::net_message.BytesRead(), byteStart);
}
::netgraph.addTrafficIn(::net_message.BytesRead() - byteStart);
@ -2173,8 +2167,18 @@ void CL_SendSummonCheat(const char* summon)
MSG_WriteString(&net_buffer, summon);
}
//
// CL_SendSummonFriendCheat
//
void CL_SendSummonFriendCheat(const char* summon)
{
MSG_WriteMarker(&net_buffer, clc_cheat);
MSG_WriteByte(&net_buffer, 3);
MSG_WriteString(&net_buffer, summon);
}
void PickupMessage (AActor *toucher, const char *message)
void PickupMessage (const AActor *toucher, const char *message)
{
// Some maps have multiple items stacked on top of each other.
// It looks odd to display pickup messages for all of them.
@ -2186,7 +2190,7 @@ void PickupMessage (AActor *toucher, const char *message)
{
lastmessagetic = gametic;
lastmessage = message;
Printf (PRINT_PICKUP, "%s\n", message);
PrintFmt(PRINT_PICKUP, "{}\n", message);
}
}
@ -2195,7 +2199,7 @@ void PickupMessage (AActor *toucher, const char *message)
//
// This is used for displaying weaponstay messages, it is inevitably a hack
// because weaponstay is a hack
void WeaponPickupMessage (AActor *toucher, weapontype_t &Weapon)
void WeaponPickupMessage (const AActor *toucher, const weapontype_t &Weapon)
{
switch (Weapon)
{
@ -2359,8 +2363,8 @@ void CL_SimulatePlayers()
if (dist > 2 * FRACUNIT)
{
#ifdef _SNAPSHOT_DEBUG_
Printf(PRINT_HIGH, "Snapshot %i, Correcting extrapolation error of %i\n",
world_index, dist >> FRACBITS);
PrintFmt(PRINT_HIGH, "Snapshot {}, Correcting extrapolation error of {}\n",
world_index, dist >> FRACBITS);
#endif // _SNAPSHOT_DEBUG_
static constexpr fixed_t correction_amount = FRACUNIT * 0.80f;
@ -2431,7 +2435,7 @@ void CL_SimulateWorld()
else
reason = "invalid world_index";
Printf(PRINT_HIGH, "Gametic %i, world_index %i, Resynching world index (%s).\n",
PrintFmt(PRINT_HIGH, "Gametic {}, world_index {}, Resynching world index ({}).\n",
gametic, world_index, reason);
#endif // _WORLD_INDEX_DEBUG_
@ -2443,7 +2447,7 @@ void CL_SimulateWorld()
world_index = last_svgametic;
#ifdef _WORLD_INDEX_DEBUG_
Printf(PRINT_HIGH, "Gametic %i, simulating world_index %i\n",
PrintFmt(PRINT_HIGH, "Gametic {}, simulating world_index {}\n",
gametic, world_index);
#endif // _WORLD_INDEX_DEBUG_
@ -2459,8 +2463,8 @@ void CL_SimulateWorld()
#ifdef _WORLD_INDEX_DEBUG_
if (drift_correction != 0)
Printf(PRINT_HIGH, "Gametic %i, increasing world index by %i.\n",
gametic, drift_correction);
PrintFmt(PRINT_HIGH, "Gametic {}, increasing world index by {}.\n",
gametic, drift_correction);
#endif // _WORLD_INDEX_DEBUG_
world_index = world_index + 1 + drift_correction;

View file

@ -71,6 +71,7 @@ bool CL_Connect();
void CL_SendCheat(int cheats);
void CL_SendGiveCheat(const char* item);
void CL_SendSummonCheat(const char* summon);
void CL_SendSummonFriendCheat(const char* summon);
void CL_DisplayTics();
void CL_RunTics();

View file

@ -23,7 +23,6 @@
#include "odamex.h"
#include <map>
#include <sstream>
#include "c_maplist.h"
@ -384,11 +383,11 @@ void CMD_MaplistCallback(const maplist_qrows_t &result) {
const auto& [map, lastmap, _, wads] = *entry;
char flag = ' ';
if (show_this_map && index == this_index) {
flag = '*';
flag = '>';
} else if (index == next_index) {
flag = '+';
}
PrintFmt(PRINT_HIGH, "{}{}. {} {}{}\n", flag, index + 1,
PrintFmt(PRINT_HIGH, " {}{}. {} {}{}\n", flag, index + 1,
JoinStrings(wads, " "), map,
lastmap.empty() ? "" : fmt::format(" lastmap={}", lastmap));
}

View file

@ -22,8 +22,6 @@
#pragma once
#include <map>
#include "c_maplist.h"
// Callbacks for deffered queries

View file

@ -158,6 +158,8 @@ void P_SpawnPlayer(player_t& player, mapthing2_t* mthing)
else if (playerstate == PST_REBORN)
level.behavior->StartTypedScripts(SCRIPT_Respawn, player.mo);
}
P_FriendlyEffects(); // Mark any new friendly monsters with an effect
}
std::vector<AActor*> spawnfountains;

View file

@ -64,6 +64,7 @@
#include "infomap.h"
#include "cl_replay.h"
#include "r_interp.h"
#include "m_doomobjcontainer.h"
// Extern data from other files.
@ -84,6 +85,8 @@ EXTERN_CVAR(hud_revealsecrets)
EXTERN_CVAR(mute_enemies)
EXTERN_CVAR(mute_spectators)
EXTERN_CVAR(show_messages)
EXTERN_CVAR(co_novileghosts)
EXTERN_CVAR(sv_sharekeys)
extern std::string digest;
extern bool forcenetdemosplit;
@ -108,7 +111,7 @@ void G_PlayerReborn(player_t& p); // [Toke - todo] clean this function
void P_DestroyButtonThinkers();
void P_ExplodeMissile(AActor* mo);
void P_PlayerLeavesGame(player_s* player);
void P_SetPsprite(player_t* player, int position, statenum_t stnum);
void P_SetPsprite(player_t* player, int position, int32_t stnum);
void P_SetButtonTexture(line_t* line, short texture);
/**
@ -200,7 +203,7 @@ static void CL_Disconnect(const odaproto::svc::Disconnect* msg)
buffer = fmt::sprintf("Disconnected from server\n");
}
Printf("%s", msg->message());
PrintFmt("{}", msg->message());
CL_QuitNetGame(NQ_SILENT);
}
@ -212,7 +215,7 @@ static void CL_PlayerInfo(const odaproto::svc::PlayerInfo* msg)
player_t& p = consoleplayer();
uint32_t weaponowned = msg->player().weaponowned();
UnpackBoolArray(p.weaponowned, NUMWEAPONS, weaponowned);
UnpackBoolArray(p.weaponowned.data(), NUMWEAPONS, weaponowned);
uint32_t cards = msg->player().cards();
UnpackBoolArray(p.cards, NUMCARDS, cards);
@ -504,7 +507,7 @@ static void CL_SpawnMobj(const odaproto::svc::SpawnMobj* msg)
mobjtype_t type = static_cast<mobjtype_t>(msg->current().type());
statenum_t state = static_cast<statenum_t>(msg->current().statenum());
if (type < MT_PLAYER || type >= NUMMOBJTYPES)
if (!mobjinfo.contains(type))
return;
P_ClearId(netid);
@ -584,10 +587,12 @@ static void CL_SpawnMobj(const odaproto::svc::SpawnMobj* msg)
(mo->target->oflags & hordeBossModMask))
{
mo->oflags |= MFO_FULLBRIGHT;
mo->effects = FX_YELLOWFOUNTAIN;
mo->effects |= FX_YELLOWFOUNTAIN;
mo->translation = translationref_t(&::bosstable[0]);
}
P_FriendlyEffects(mo);
AActor* tracer = NULL;
if (bflags & baseline_t::TRACER)
tracer = P_FindThingById(msg->current().tracerid());
@ -627,7 +632,7 @@ static void CL_SpawnMobj(const odaproto::svc::SpawnMobj* msg)
mo->tics = 1;
}
if (state >= S_NULL && state < NUMSTATES)
if(state >= S_NULL && states.contains(state))
{
P_SetMobjState(mo, state);
}
@ -674,12 +679,17 @@ static void CL_SpawnMobj(const odaproto::svc::SpawnMobj* msg)
mo->flags = msg->current().flags();
}
if (msg->spawn_flags() & SVC_SM_FLAGS2)
{
mo->flags2 = msg->current().flags2();
}
if (msg->spawn_flags() & SVC_SM_OFLAGS)
{
mo->oflags = msg->current().oflags();
// [AM] HACK! Assume that any monster with a flag is a boss.
if (mo->oflags)
if (mo->oflags & hordeBossModMask)
{
mo->effects = FX_YELLOWFOUNTAIN;
mo->translation = translationref_t(&::bosstable[0]);
@ -695,7 +705,7 @@ static void CL_SpawnMobj(const odaproto::svc::SpawnMobj* msg)
tics = -1;
// already spawned as gibs?
if (!mo || mo->state - states == S_GIBS)
if (!mo || mo->state == &states[S_GIBS])
return;
if ((frame & FF_FRAMEMASK) >= sprites[mo->sprite].numframes)
@ -787,9 +797,9 @@ static void CL_LoadMap(const odaproto::svc::LoadMap* msg)
OWantFile file;
if (!OWantFile::makeWithHash(file, name, OFILE_WAD, hash))
{
Printf(PRINT_WARNING,
"Could not construct wanted file \"%s\" that server requested.\n",
name);
PrintFmt(PRINT_WARNING,
"Could not construct wanted file \"{}\" that server requested.\n",
name);
CL_QuitNetGame(NQ_DISCONNECT);
return;
}
@ -810,9 +820,9 @@ static void CL_LoadMap(const odaproto::svc::LoadMap* msg)
OWantFile file;
if (!OWantFile::makeWithHash(file, name, OFILE_DEH, hash))
{
Printf(PRINT_WARNING,
"Could not construct wanted patch \"%s\" that server requested.\n",
name);
PrintFmt(PRINT_WARNING,
"Could not construct wanted patch \"{}\" that server requested.\n",
name);
CL_QuitNetGame(NQ_DISCONNECT);
return;
}
@ -830,7 +840,7 @@ static void CL_LoadMap(const odaproto::svc::LoadMap* msg)
{
if (::missingCommercialIWAD)
{
Printf(PRINT_WARNING, "Server requires commercial IWAD that was not found.\n");
PrintFmt(PRINT_WARNING, "Server requires commercial IWAD that was not found.\n");
CL_QuitNetGame(NQ_DISCONNECT);
return;
}
@ -958,7 +968,7 @@ static void CL_UserInfo(const odaproto::svc::UserInfo* msg)
p->userinfo.gender = static_cast<gender_t>(msg->gender());
if (p->userinfo.gender < 0 || p->userinfo.gender >= NUMGENDER)
p->userinfo.gender = GENDER_NEUTER;
p->userinfo.gender = GENDER_OTHER;
p->userinfo.color[0] = 255;
p->userinfo.color[1] = msg->color().r();
@ -1138,8 +1148,15 @@ static void CL_SpawnPlayer(const odaproto::svc::SpawnPlayer* msg)
// give all cards in death match mode
if (!G_IsCoopGame())
{
for (size_t i = 0; i < NUMCARDS; i++)
p->cards[i] = true;
}
else if (sv_sharekeys)
{
const uint32_t cards = msg->cards();
UnpackBoolArray(p->cards, NUMCARDS, cards);
}
if (p->id == consoleplayer_id)
{
@ -1305,6 +1322,48 @@ static void CL_KillMobj(const odaproto::svc::KillMobj* msg)
P_KillMobj(source, target, inflictor, joinkill);
}
//
// CL_RaiseMobj
//
static void CL_RaiseMobj(const odaproto::svc::RaiseMobj* msg)
{
uint32_t srcid = msg->source_netid();
uint32_t cpsid = msg->corpse().netid();
AActor* source = P_FindThingById(srcid);
AActor* corpsehit = P_FindThingById(cpsid);
if (!corpsehit)
return;
corpsehit->x = msg->corpse().pos().x();
corpsehit->y = msg->corpse().pos().y();
corpsehit->z = msg->corpse().pos().z();
corpsehit->angle = msg->corpse().angle();
corpsehit->momx = msg->corpse().mom().x();
corpsehit->momy = msg->corpse().mom().y();
corpsehit->momz = msg->corpse().mom().z();
mobjinfo_t* info = corpsehit->info;
P_SetMobjState(corpsehit, info->raisestate);
// [Nes] - Classic demo compatability: Ghost monster bug.
if (co_novileghosts)
{
corpsehit->height = P_ThingInfoHeight(info); // [RH] Use real mobj height
corpsehit->radius = info->radius; // [RH] Use real radius
}
else
{
corpsehit->height <<= 2;
}
corpsehit->flags = info->flags;
corpsehit->health = info->spawnhealth;
corpsehit->target = AActor::AActorPtr();
}
///////////////////////////////////////////////////////////
///// CL_Fire* called when someone uses a weapon /////////
///////////////////////////////////////////////////////////
@ -1320,7 +1379,7 @@ static void CL_FireWeapon(const odaproto::svc::FireWeapon* msg)
weapontype_t firedweap = static_cast<weapontype_t>(msg->readyweapon());
if (firedweap < 0 || firedweap > wp_nochange)
{
Printf("CL_FireWeapon: unknown weapon %d\n", firedweap);
PrintFmt("CL_FireWeapon: unknown weapon {}\n", firedweap);
return;
}
int servertic = msg->servertic();
@ -1387,13 +1446,13 @@ static void CL_Print(const odaproto::svc::Print* msg)
// TODO : Clientchat moved, remove that but PRINT_SERVERCHAT
if (level == PRINT_CHAT)
Printf(level, "%c*%s", TEXTCOLOR_ESCAPE, str);
PrintFmt(level, "{:c}*{}", TEXTCOLOR_ESCAPE, str);
else if (level == PRINT_TEAMCHAT)
Printf(level, "%c!%s", TEXTCOLOR_ESCAPE, str);
PrintFmt(level, "{:c}!{}", TEXTCOLOR_ESCAPE, str);
else if (level == PRINT_SERVERCHAT)
Printf(level, "%s%s", TEXTCOLOR_YELLOW, str);
PrintFmt(level, "{:s}{}", TEXTCOLOR_YELLOW, str);
else
Printf(level, "%s", str);
PrintFmt(level, "{}", str);
if (show_messages)
{
@ -1814,9 +1873,9 @@ static void CL_Say(const odaproto::svc::Say* msg)
if (message_visibility == 0)
{
if (strnicmp(message, "/me ", 4) == 0)
Printf(publicmsg, "* %s %s\n", name, &message[4]);
PrintFmt(publicmsg, "* {} {}\n", name, &message[4]);
else
Printf(publicmsg, "%s: %s\n", name, message);
PrintFmt(publicmsg, "{}: {}\n", name, message);
if (show_messages && !filtermessage)
{
@ -1827,9 +1886,9 @@ static void CL_Say(const odaproto::svc::Say* msg)
else if (message_visibility == 1)
{
if (strnicmp(message, "/me ", 4) == 0)
Printf(publicteammsg, "* %s %s\n", name, &message[4]);
PrintFmt(publicteammsg, "* {} {}\n", name, &message[4]);
else
Printf(publicteammsg, "%s: %s\n", name, message);
PrintFmt(publicteammsg, "{}: {}\n", name, message);
if (show_messages && cl_chatsounds && !filtermessage)
S_Sound(CHAN_INTERFACE, "misc/teamchat", 1, ATTN_NONE);
@ -2006,10 +2065,8 @@ static void CL_SecretEvent(const odaproto::svc::SecretEvent* msg)
if (!::hud_revealsecrets || ::hud_revealsecrets > 2)
return;
std::string buf;
buf = fmt::sprintf("%s%s %sfound a secret!\n", TEXTCOLOR_YELLOW,
player.userinfo.netname, TEXTCOLOR_NORMAL);
Printf("%s", buf);
PrintFmt("{}{} {}found a secret!\n", TEXTCOLOR_YELLOW,
player.userinfo.netname, TEXTCOLOR_NORMAL);
if (::hud_revealsecrets == 1)
S_Sound(CHAN_INTERFACE, "misc/secret", 1, ATTN_NONE);
@ -2090,7 +2147,7 @@ static void CL_ServerGametic(const odaproto::svc::ServerGametic* msg)
::last_svgametic = newtic;
#ifdef _WORLD_INDEX_DEBUG_
Printf(PRINT_HIGH, "Gametic %i, received world index %i\n", gametic, last_svgametic);
PrintFmt(PRINT_HIGH, "Gametic {}, received world index {}\n", gametic, last_svgametic);
#endif // _WORLD_INDEX_DEBUG_
}
@ -2162,8 +2219,8 @@ static void CL_PlayerState(const odaproto::svc::PlayerState* msg)
{
if (i < msg->player().psprites_size())
{
unsigned int state = msg->player().psprites().Get(i).statenum();
if (state >= NUMSTATES)
const int32_t state = msg->player().psprites().Get(i).statenum();
if (!states.contains(state))
{
continue;
}
@ -2296,11 +2353,11 @@ static void CL_PlayerQueuePos(const odaproto::svc::PlayerQueuePos* msg)
{
if (queuePos > 0 && player.QueuePosition == 0)
{
Printf(PRINT_HIGH, "Position in line to play: %u\n", queuePos);
PrintFmt(PRINT_HIGH, "Position in line to play: {}\n", queuePos);
}
else if (player.spectator && queuePos == 0 && player.QueuePosition > 0)
{
Printf(PRINT_HIGH, "You have been removed from the queue.\n");
PrintFmt(PRINT_HIGH, "You have been removed from the queue.\n");
}
}
@ -2396,6 +2453,7 @@ static void CL_SectorProperties(const odaproto::svc::SectorProperties* msg)
sector->base_ceiling_yoffs = msg->sector().base_ceiling_yoffs();
sector->base_floor_angle = msg->sector().base_floor_angle();
sector->base_floor_yoffs = msg->sector().base_floor_yoffs();
break;
case SPC_Special:
sector->special = msg->sector().special();
default:
@ -2449,7 +2507,7 @@ static void CL_SetMobjState(const odaproto::svc::MobjState* msg)
AActor* mo = P_FindThingById(msg->netid());
int s = msg->mostate();
if (mo == NULL || s < 0 || s >= NUMSTATES)
if (mo == NULL || !states.contains(s))
return;
P_SetMobjState(mo, static_cast<statenum_t>(s));
@ -2574,7 +2632,7 @@ static void CL_ExecuteACSSpecial(const odaproto::svc::ExecuteACSSpecial* msg)
break;
default:
Printf(PRINT_HIGH, "Invalid ACS special: %d", special);
PrintFmt(PRINT_HIGH, "Invalid ACS special: {}", special);
break;
}
}
@ -3008,6 +3066,7 @@ parseError_e CL_ParseCommand()
SV_MSG(svc_spawnplayer, CL_SpawnPlayer, odaproto::svc::SpawnPlayer);
SV_MSG(svc_damageplayer, CL_DamagePlayer, odaproto::svc::DamagePlayer);
SV_MSG(svc_killmobj, CL_KillMobj, odaproto::svc::KillMobj);
SV_MSG(svc_raisemobj, CL_RaiseMobj, odaproto::svc::RaiseMobj);
SV_MSG(svc_fireweapon, CL_FireWeapon, odaproto::svc::FireWeapon);
SV_MSG(svc_updatesector, CL_UpdateSector, odaproto::svc::UpdateSector);
SV_MSG(svc_print, CL_Print, odaproto::svc::Print);
@ -3062,3 +3121,5 @@ parseError_e CL_ParseCommand()
RecordProto(static_cast<svc_t>(cmd), msg);
return PERR_OK;
}
VERSION_CONTROL (cl_parse_cpp, "$Id$")

View file

@ -32,8 +32,6 @@
#include "p_snapshot.h"
#include <map>
EXTERN_CVAR (cl_prednudge)
EXTERN_CVAR (cl_predictsectors)

View file

@ -182,7 +182,7 @@ void ClientReplay::itemReplay()
continue;
}
std::string weaponname = P_MobjToName(mo->type);
std::string weaponname = P_MobjToName(static_cast<mobjtype_t>(mo->type));
weapontype_t weapontype = P_NameToWeapon(weaponname);
bool weaponSwitch = P_CheckSwitchWeapon(&player, weapontype);

View file

@ -30,7 +30,6 @@
#include "d_player.h"
#include "m_fixed.h"
#include "r_defs.h"
#include <map>
class ClientReplay
{

View file

@ -41,34 +41,35 @@ void D_WriteUserInfoStrings(int i, byte **stream, bool compact) {}
void D_ReadUserInfoStrings(int i, byte **stream, bool update) {}
void SV_SpawnMobj(AActor *mobj) {}
void SV_TouchSpecial(AActor *special, player_t *player) {}
void SV_TouchSpecial(const AActor *special, player_t *player) {}
ItemEquipVal SV_FlagTouch (player_t &player, team_t f, bool firstgrab) { return IEV_NotEquipped; }
void SV_SocketTouch (player_t &player, team_t f) {}
void SV_SendKillMobj(AActor *source, AActor *target, AActor *inflictor, bool joinkill) {}
void SV_SendDamagePlayer(player_t *player, AActor* inflictor, int healthDamage, int armorDamage) {}
void SV_SendDamageMobj(AActor *target, int pain) {}
void SV_SendKillMobj(const AActor *source, const AActor *target, const AActor *inflictor, bool joinkill) {}
void SV_SendRaiseMobj(const AActor* source, const AActor* corpse) { }
void SV_SendDamagePlayer(player_t *player, const AActor* inflictor, int healthDamage, int armorDamage) {}
void SV_SendDamageMobj(const AActor *target, int pain) {}
void SV_CTFEvent(team_t f, flag_score_t event, player_t &who) {}
void SV_UpdateFrags(player_t &player) {}
void SV_ActorTarget(AActor *actor) {}
void SV_SendDestroyActor(AActor *mo) {}
void SV_ExplodeMissile(AActor *mo) {}
void SV_ActorTarget(const AActor *actor) {}
void SV_SendDestroyActor(const AActor *mo) {}
void SV_ExplodeMissile(const AActor *mo) {}
void SV_SendPlayerInfo(player_t &player) {}
void SV_PreservePlayer(player_t &player) {}
void SV_BroadcastSector(int sectornum) {}
void SV_UpdateMobj(AActor* mo) {}
void SV_UpdateMobjState(AActor* mo) {}
void SV_UpdateMobj(const AActor* mo) {}
void SV_UpdateMobjState(const AActor* mo) {}
void CTF_RememberFlagPos(mapthing2_t *mthing) {}
void CTF_SpawnFlag(team_t f) {}
bool SV_AwarenessUpdate(player_t &pl, AActor* mo) { return true; }
void SV_SendPackets(void) {}
void SV_SendExecuteLineSpecial(byte special, line_t* line, AActor* activator, int arg0,
void SV_SendExecuteLineSpecial(byte special, const line_t* line, const AActor* activator, int arg0,
int arg1, int arg2, int arg3, int arg4)
{
}
void SV_UpdateMonsterRespawnCount() {}
void SV_Sound(AActor* mo, byte channel, const char* name, byte attenuation) {}
void SV_Sound(const AActor* mo, byte channel, const char* name, byte attenuation) {}
CVAR_FUNC_IMPL(sv_sharekeys) {}

View file

@ -35,6 +35,10 @@
#include "i_net.h"
#include "i_system.h"
#include "s_sound.h"
#include "c_cvars.h"
EXTERN_CVAR(snd_votesfx)
//////// VOTING STATE ////////
// Return a singleton reference for the class.
@ -43,7 +47,14 @@ VoteState& VoteState::instance() {
return singleton;
}
void VoteState::set(const vote_state_t &vote_state) {
void VoteState::set(const vote_state_t& vote_state)
{
// capture previous state BEFORE overwriting
const bool was_visible = this->visible;
const auto prev_result = this->result;
const auto prev_votestring = this->votestring;
// overwrite with new state
this->visible = true;
this->result = vote_state.result;
this->votestring = vote_state.votestring;
@ -54,6 +65,34 @@ void VoteState::set(const vote_state_t &vote_state) {
this->no = vote_state.no;
this->no_needed = vote_state.no_needed;
this->abs = vote_state.abs;
// [RV] Play "start" when the vote first appears or the prompt changed
const bool votestring_changed = (prev_votestring != vote_state.votestring);
if (!was_visible || votestring_changed)
{
if (snd_votesfx)
S_Sound(CHAN_INTERFACE, "ui/vote/start", 1.0f, ATTN_NONE);
}
// [RV] Play "pass/fail" exactly once when result becomes decided
if (prev_result == VOTE_UNDEC && vote_state.result != VOTE_UNDEC)
{
switch (vote_state.result)
{
case VOTE_YES:
if (snd_votesfx)
S_Sound(CHAN_INTERFACE, "ui/vote/pass", 1.0f, ATTN_NONE);
break;
case VOTE_NO:
case VOTE_INTERRUPT:
case VOTE_ABANDON:
if (snd_votesfx)
S_Sound(CHAN_INTERFACE, "ui/vote/fail", 1.0f, ATTN_NONE);
break;
default:
break;
}
}
}
bool VoteState::get(vote_state_t &vote_state) {
@ -93,7 +132,7 @@ bool VoteState::get(vote_state_t &vote_state) {
//////// CALLBACKS & ERRBACKS ////////
void CMD_MapVoteErrback(const std::string &error) {
Printf(PRINT_HIGH, "callvote failed: %s\n", error);
PrintFmt(PRINT_HIGH, "callvote failed: {}\n", error);
}
void CMD_MapVoteCallback(const maplist_qrows_t &result) {
@ -118,7 +157,7 @@ void CMD_MapVoteCallback(const maplist_qrows_t &result) {
}
void CMD_RandmapVoteErrback(const std::string &error) {
Printf(PRINT_HIGH, "callvote failed: %s\n", error);
PrintFmt(PRINT_HIGH, "callvote failed: {}\n", error);
}
void CMD_RandmapVoteCallback(const maplist_qrows_t &result) {
@ -145,7 +184,7 @@ void CMD_RandmapVoteCallback(const maplist_qrows_t &result) {
BEGIN_COMMAND(callvote) {
// Dumb question, but are we even connected to a server?
if (!connected) {
Printf(PRINT_HIGH, "callvote failed: You are not connected to a server.\n");
PrintFmt(PRINT_HIGH, "callvote failed: You are not connected to a server.\n");
return;
}
@ -169,7 +208,7 @@ BEGIN_COMMAND(callvote) {
if (votecmd == VOTE_NONE) {
// We passed an argument but it wasn't a valid vote type.
Printf(PRINT_HIGH, "callvote failed: Invalid vote \"%s\".\n", votecmd_s);
PrintFmt(PRINT_HIGH, "callvote failed: Invalid vote \"{}\".\n", votecmd_s);
return;
}
}
@ -203,7 +242,7 @@ BEGIN_COMMAND(callvote) {
case VOTE_MAP:
// If we have no arguments, ask for more.
if (arguments.empty()) {
Printf(PRINT_HIGH, "callvote failed: \"map\" callvote needs a maplist index or unambiguous map name.\n");
PrintFmt(PRINT_HIGH, "callvote failed: \"map\" callvote needs a maplist index or unambiguous map name.\n");
return;
}
@ -241,7 +280,7 @@ BEGIN_COMMAND(vote_yes)
{
if (!connected)
{
Printf(PRINT_HIGH, "vote failed: You are not connected to a server.\n");
PrintFmt(PRINT_HIGH, "vote failed: You are not connected to a server.\n");
return;
}
@ -249,6 +288,9 @@ BEGIN_COMMAND(vote_yes)
MSG_WriteString(&net_buffer, "vote");
MSG_WriteByte(&net_buffer, 1);
MSG_WriteString(&net_buffer, "yes");
if (snd_votesfx)
S_Sound(CHAN_INTERFACE, "ui/vote/yes", 1.0f, ATTN_NONE);
}
END_COMMAND(vote_yes)
@ -259,7 +301,7 @@ BEGIN_COMMAND(vote_no)
{
if (!connected)
{
Printf(PRINT_HIGH, "vote failed: You are not connected to a server.\n");
PrintFmt(PRINT_HIGH, "vote failed: You are not connected to a server.\n");
return;
}
@ -267,5 +309,8 @@ BEGIN_COMMAND(vote_no)
MSG_WriteString(&net_buffer, "vote");
MSG_WriteByte(&net_buffer, 1);
MSG_WriteString(&net_buffer, "no");
if (snd_votesfx)
S_Sound(CHAN_INTERFACE, "ui/vote/no", 1.0f, ATTN_NONE);
}
END_COMMAND(vote_no)

View file

@ -84,15 +84,10 @@
#include "g_horde.h"
#include "w_ident.h"
#include "gui_boot.h"
#include "g_musinfo.h"
#include "g_episode.h"
#ifdef GEKKO
#include "i_wii.h"
#endif
#ifdef _XBOX
#include "i_xbox.h"
#endif
extern size_t got_heapsize;
void D_CheckNetGame();
void D_ProcessEvents();
@ -154,9 +149,9 @@ void D_SetPlatform(void)
#ifdef GCONSOLE
#ifdef _XBOX
platform = PF_XBOX;
#elif GEKKO
#elif defined(GEKKO)
platform = PF_WII;
#elif __SWITCH__
#elif defined(__SWITCH__)
platform = PF_SWITCH;
#else
platform = PF_UNKNOWN;
@ -364,7 +359,7 @@ void D_DoomLoop()
}
catch (CRecoverableError &error)
{
Printf(PRINT_ERROR, "\nERROR: %s\n", error.GetMsg());
PrintFmt(PRINT_ERROR, "\nERROR: {}\n", error.GetMsg());
// [AM] In case an error is caused by a console command.
C_ClearCommand();
@ -595,6 +590,77 @@ bool HashOk(std::string &required, std::string &available)
void CL_NetDemoPlay(const std::string &filename);
EXTERN_CVAR(co_boomphys)
EXTERN_CVAR(co_zdoomphys)
EXTERN_CVAR(co_mbfphys)
EXTERN_CVAR(co_zdoomammo)
EXTERN_CVAR(co_novileghosts)
EXTERN_CVAR(co_removesoullimit)
EXTERN_CVAR(co_allowdropoff)
EXTERN_CVAR(r_clipmaskedspecial)
EXTERN_CVAR(r_thingsectorlight)
void G_ReadCOMPLVL()
{
if (!serverside)
return;
int lumpnum = W_CheckNumForName("COMPLVL");
if (lumpnum != -1)
{
char* complvl = static_cast<char*>(W_CacheLumpNum(lumpnum, PU_STATIC));
co_zdoomphys.Set(0.0f);
co_zdoomammo.Set(0.0f);
if (iequals("vanilla", complvl))
{
co_boomphys.Set(0.0f);
co_mbfphys.Set(0.0f);
co_novileghosts.Set(0.0f);
co_allowdropoff.Set(0.0f);
co_removesoullimit.Set(0.0f);
r_clipmaskedspecial.Set(0.0f);
r_thingsectorlight.Set(0.0f);
}
else if (iequals("boom", complvl))
{
co_boomphys.Set(1.0f);
co_mbfphys.Set(0.0f);
co_novileghosts.Set(1.0f);
co_allowdropoff.Set(1.0f);
co_removesoullimit.Set(1.0f);
r_clipmaskedspecial.Set(0.0f);
r_thingsectorlight.Set(0.0f);
}
else if (iequals("mbf", complvl))
{
co_boomphys.Set(1.0f);
co_mbfphys.Set(1.0f);
co_novileghosts.Set(1.0f);
co_allowdropoff.Set(1.0f);
co_removesoullimit.Set(1.0f);
r_clipmaskedspecial.Set(0.0f);
r_thingsectorlight.Set(1.0f);
}
else if (iequals("mbf21", complvl))
{
co_boomphys.Set(1.0f);
co_mbfphys.Set(1.0f);
co_novileghosts.Set(1.0f);
co_allowdropoff.Set(1.0f);
co_removesoullimit.Set(1.0f);
r_clipmaskedspecial.Set(1.0f);
r_thingsectorlight.Set(0.0f);
}
else
{
DPrintFmt("Unrecognized COMPLVL value: {}", complvl);
}
Z_Free(complvl);
}
}
//
// D_Init
@ -616,18 +682,14 @@ void D_Init()
// start the Zone memory manager
Z_Init();
if (first_time)
Printf("Z_Init: Using native allocator with OZone bookkeeping.\n");
PrintFmt("Z_Init: Using native allocator with OZone bookkeeping.\n");
// Load palette and set up colormaps
V_Init();
// if (first_time)
// Printf(PRINT_HIGH, "Res_InitTextureManager: Init image resource management.\n");
// Res_InitTextureManager();
// init the renderer
if (first_time)
Printf(PRINT_HIGH, "R_Init: Init DOOM refresh daemon.\n");
PrintFmt(PRINT_HIGH, "R_Init: Init DOOM refresh daemon.\n");
R_Init();
// V_LoadFonts();
@ -642,31 +704,30 @@ void D_Init()
G_ParseMusInfo();
S_ParseSndInfo();
G_ParseHordeDefs();
G_ReadCOMPLVL();
// init the menu subsystem
if (first_time)
Printf(PRINT_HIGH, "M_Init: Init miscellaneous info.\n");
PrintFmt(PRINT_HIGH, "M_Init: Init miscellaneous info.\n");
M_Init();
if (first_time)
Printf(PRINT_HIGH, "P_Init: Init Playloop state.\n");
PrintFmt(PRINT_HIGH, "P_Init: Init Playloop state.\n");
P_InitEffects();
P_Init();
// init sound and music
if (first_time)
{
Printf (PRINT_HIGH, "S_Init: Setting up sound.\n");
Printf (PRINT_HIGH, "S_Init: default sfx volume is %g\n", (float)snd_sfxvolume);
Printf (PRINT_HIGH, "S_Init: default music volume is %g\n", (float)snd_musicvolume);
PrintFmt(PRINT_HIGH, "S_Init: Setting up sound.\n");
PrintFmt(PRINT_HIGH, "S_Init: default sfx volume is {:g}\n", snd_sfxvolume.value());
PrintFmt(PRINT_HIGH, "S_Init: default music volume is {:g}\n", snd_musicvolume.value());
}
S_Init(snd_sfxvolume, snd_musicvolume);
// R_InitViewBorder();
// init the status bar
if (first_time)
Printf(PRINT_HIGH, "ST_Init: Init status bar.\n");
PrintFmt(PRINT_HIGH, "ST_Init: Init status bar.\n");
ST_Init();
first_time = false;
@ -696,6 +757,7 @@ void STACK_ARGS D_Shutdown()
// stop sound effects and music
S_Stop();
S_Deinit();
S_ClearSoundLumps();
// shutdown automap
AM_Stop();
@ -738,7 +800,6 @@ void STACK_ARGS D_Shutdown()
void C_DoCommand(std::string_view cmd, uint32_t key);
void D_Init_DEHEXTRA_Frames(void);
//
// D_DoomMain
@ -757,10 +818,7 @@ void D_DoomMain()
W_SetupFileIdentifiers();
// [RH] Initialize items. Still only used for the give command. :-(
InitItems();
// Initialize all extra frames
D_Init_DEHEXTRA_Frames();
D_InitializeDoomObjectTables();
M_FindResponseFile(); // [ML] 23/1/07 - Add Response file support back in
@ -851,15 +909,17 @@ void D_DoomMain()
D_AddWadCommandLineFiles(newwadfiles);
D_AddDehCommandLineFiles(newpatchfiles);
// do the deh processing
D_LoadResourceFiles(newwadfiles, newpatchfiles);
Printf(PRINT_HIGH, "I_Init: Init hardware.\n");
PrintFmt(PRINT_HIGH, "I_Init: Init hardware.\n");
atterm(I_ShutdownHardware);
I_Init();
I_InitInput();
// [SL] Call init routines that need to be reinitialized every time WAD changes
atterm(D_Shutdown);
// initialize
D_Init();
atterm(I_Endoom);
@ -868,17 +928,17 @@ void D_DoomMain()
cvar_t::EnableCallbacks();
// [RH] User-configurable startup strings. Because BOOM does.
if (GStrings(STARTUP1)[0]) Printf(PRINT_HIGH, "%s\n", GStrings(STARTUP1));
if (GStrings(STARTUP2)[0]) Printf(PRINT_HIGH, "%s\n", GStrings(STARTUP2));
if (GStrings(STARTUP3)[0]) Printf(PRINT_HIGH, "%s\n", GStrings(STARTUP3));
if (GStrings(STARTUP4)[0]) Printf(PRINT_HIGH, "%s\n", GStrings(STARTUP4));
if (GStrings(STARTUP5)[0]) Printf(PRINT_HIGH, "%s\n", GStrings(STARTUP5));
if (GStrings(STARTUP1)[0]) PrintFmt(PRINT_HIGH, "{}\n", GStrings(STARTUP1));
if (GStrings(STARTUP2)[0]) PrintFmt(PRINT_HIGH, "{}\n", GStrings(STARTUP2));
if (GStrings(STARTUP3)[0]) PrintFmt(PRINT_HIGH, "{}\n", GStrings(STARTUP3));
if (GStrings(STARTUP4)[0]) PrintFmt(PRINT_HIGH, "{}\n", GStrings(STARTUP4));
if (GStrings(STARTUP5)[0]) PrintFmt(PRINT_HIGH, "{}\n", GStrings(STARTUP5));
// developer mode
devparm = Args.CheckParm("-devparm");
if (devparm)
Printf(PRINT_HIGH, "%s", GStrings(D_DEVSTR)); // D_DEVSTR
PrintFmt(PRINT_HIGH, "{}", GStrings(D_DEVSTR)); // D_DEVSTR
// set the default value for vid_ticker based on the presence of -devparm
if (devparm)
@ -946,7 +1006,7 @@ void D_DoomMain()
CL_DownloadInit();
atterm(CL_DownloadShutdown);
Printf(PRINT_HIGH, "D_CheckNetGame: Checking network game status.\n");
PrintFmt(PRINT_HIGH, "D_CheckNetGame: Checking network game status.\n");
D_CheckNetGame();
// [RH] Lock any cvars that should be locked now that we're
@ -972,7 +1032,7 @@ void D_DoomMain()
p = Args.CheckParm("+playdemo");
if (p && p < Args.NumArgs() - 1)
{
Printf(PRINT_HIGH, "Playdemo parameter found on command line.\n");
PrintFmt(PRINT_HIGH, "Playdemo parameter found on command line.\n");
singledemo = true;
extern std::string defdemoname;

View file

@ -69,16 +69,16 @@ CVAR_FUNC_IMPL(cl_name)
var.Set(newname.c_str());
}
gender_t D_GenderByName (const char *gender)
{
if (!stricmp (gender, "female"))
return GENDER_FEMALE;
else if (!stricmp (gender, "cyborg"))
return GENDER_NEUTER;
else
else if (!stricmp (gender, "male"))
return GENDER_MALE;
else if (!stricmp (gender, "cyborg"))
return GENDER_CYBORG;
else
return GENDER_OTHER;
}
//

View file

@ -558,11 +558,11 @@ void HU_Drawer()
mousegraph.draw(hud_mousegraph);
if (idmypos && gamestate == GS_LEVEL)
Printf (PRINT_HIGH, "ang=%d;x,y,z=(%d,%d,%d)\n",
displayplayer().camera->angle/FRACUNIT,
displayplayer().camera->x/FRACUNIT,
displayplayer().camera->y/FRACUNIT,
displayplayer().camera->z/FRACUNIT);
PrintFmt(PRINT_HIGH, "ang={};x,y,z=({},{},{})\n",
displayplayer().camera->angle/FRACUNIT,
displayplayer().camera->x/FRACUNIT,
displayplayer().camera->y/FRACUNIT,
displayplayer().camera->z/FRACUNIT);
// Draw Netdemo info
hud::drawNetdemo();
@ -666,7 +666,7 @@ BEGIN_COMMAND (say_to)
player_t &player = nameplayer(argv[1]);
if (!validplayer(player))
{
Printf(PRINT_HIGH, "%s isn't the name of anybody on the server.\n", argv[1]);
PrintFmt(PRINT_HIGH, "{} isn't the name of anybody on the server.\n", argv[1]);
return;
}
@ -2159,7 +2159,7 @@ void HU_ConsoleScores(player_t *player)
}
}
Printf(PRINT_HIGH, "\n");
PrintFmt(PRINT_HIGH, "\n");
C_ToggleConsole();
}
@ -2169,7 +2169,7 @@ BEGIN_COMMAND (displayscores)
if (multiplayer)
HU_ConsoleScores(&consoleplayer());
else
Printf(PRINT_HIGH, "This command is only used for multiplayer games.");
PrintFmt(PRINT_HIGH, "This command is only used for multiplayer games.");
}
END_COMMAND (displayscores)

View file

@ -55,10 +55,6 @@
#include "g_skill.h"
#include "m_fileio.h"
#ifdef _XBOX
#include "i_xbox.h"
#endif
EXTERN_CVAR(g_resetinvonexit)
// temp for screenblocks (0-9)
@ -1276,7 +1272,7 @@ void M_QuitDOOM(int choice)
void M_DrawSlider(int x, int y, float leftval, float rightval, float cur, float step);
static const char *genders[3] = { "male", "female", "cyborg" };
static const char *genders[4] = { "male", "female", "cyborg", "other" };
// Acts 19 quiz the order must match d_netinf.h
static const char *colorpresets[11] = { "custom", "blue", "indigo", "green", "brown", "red", "gold", "jungle green", "purple", "white", "black" };
static state_t *PlayerState;
@ -1540,7 +1536,7 @@ static void M_PlayerSetupDrawer()
}
}
{
const int spritenum = states[mobjinfo[MT_PLAYER].spawnstate].sprite;
const int32_t spritenum = states[mobjinfo[MT_PLAYER].spawnstate].sprite;
const spriteframe_t* sprframe = &sprites[spritenum].spriteframes[PlayerState->frame & FF_FRAMEMASK];
// [Nes] Color of player preview uses the unused translation table (player 0), instead
@ -1628,7 +1624,7 @@ void M_ChangeTeam (int choice) // [Toke - Teams]
int iTeam = (int)team;
if (choice)
{
iTeam = ++iTeam % NUMTEAMS;
iTeam = (iTeam + 1) % NUMTEAMS;
}
else
{
@ -1643,12 +1639,13 @@ void M_ChangeTeam (int choice) // [Toke - Teams]
static void M_ChangeGender (int choice)
{
static constexpr int MAX_GENDER = ARRAY_LENGTH(genders) - 1;
int gender = D_GenderByName(cl_gender.cstring());
if (!choice)
gender = (gender == 0) ? 2 : gender - 1;
gender = (gender == 0) ? MAX_GENDER : gender - 1;
else
gender = (gender == 2) ? 0 : gender + 1;
gender = (gender == MAX_GENDER) ? 0 : gender + 1;
cl_gender = genders[gender];
}
@ -1683,13 +1680,14 @@ static void M_ChangeAutoAim (int choice)
static void M_ChangeColorPreset (int choice)
{
static constexpr int MAX_PRESET = ARRAY_LENGTH(colorpresets) - 1;
int colorpreset = D_ColorPreset(cl_colorpreset.cstring());
argb_t customcolor = V_GetColorFromString(cl_customcolor);
if (!choice)
colorpreset = (colorpreset == 0) ? 10 : colorpreset - 1;
colorpreset = (colorpreset == 0) ? MAX_PRESET : colorpreset - 1;
else
colorpreset = (colorpreset == 10) ? 0 : colorpreset + 1;
colorpreset = (colorpreset == MAX_PRESET) ? 0 : colorpreset + 1;
cl_colorpreset = colorpresets[colorpreset];
@ -2369,7 +2367,7 @@ size_t M_FindCvarInMenu(cvar_t &cvar, menuitem_t *menu, size_t length)
}
}
return MAXINT; // indicate not found
return limits::MAXINT; // indicate not found
}

View file

@ -117,7 +117,7 @@ void STACK_ARGS M_SaveDefaults(std::string filename)
fclose(f);
Printf(PRINT_HIGH, "Configuration saved to %s.\n", configfile);
PrintFmt(PRINT_HIGH, "Configuration saved to {}.\n", configfile);
}
}
@ -214,7 +214,7 @@ void M_LoadDefaults(void)
}
if (updated)
Printf("%s: Updating old defaults.\n", __FUNCTION__);
PrintFmt("{}: Updating old defaults.\n", __FUNCTION__);
AddCommandString("alias ? help");

View file

@ -125,6 +125,7 @@ EXTERN_CVAR(hud_extendedinfo)
// [Ralphis - Menu] Compatibility Menu
EXTERN_CVAR (co_allowdropoff)
EXTERN_CVAR (co_pursuit)
EXTERN_CVAR (co_realactorheight)
EXTERN_CVAR (co_zdoomphys)
EXTERN_CVAR (co_zdoomsound)
@ -135,6 +136,14 @@ EXTERN_CVAR (co_fineautoaim)
EXTERN_CVAR (co_nosilentspawns)
EXTERN_CVAR (co_boomphys) // [ML] Roll-up of various compat options
EXTERN_CVAR (co_mbfphys)
EXTERN_CVAR (co_helpfriends)
EXTERN_CVAR (co_monsterbacking)
EXTERN_CVAR (co_monsterfriction)
EXTERN_CVAR (co_avoidhazards)
EXTERN_CVAR (co_monstersclimbsteep)
EXTERN_CVAR (co_staylift)
EXTERN_CVAR (co_friend_ledgejumping)
EXTERN_CVAR (co_friend_distance)
EXTERN_CVAR (co_removesoullimit)
EXTERN_CVAR (co_blockmapfix)
EXTERN_CVAR (co_globalsound)
@ -167,6 +176,7 @@ EXTERN_CVAR (snd_gamesfx)
EXTERN_CVAR (snd_voxtype)
EXTERN_CVAR (cl_connectalert)
EXTERN_CVAR (cl_disconnectalert)
EXTERN_CVAR (snd_votesfx)
// Joystick menu -- Hyper_Eye
void JoystickSetup (void);
@ -183,11 +193,6 @@ EXTERN_CVAR (joy_freelook)
EXTERN_CVAR (joy_deadzone)
// Network Options
EXTERN_CVAR (cl_interp)
EXTERN_CVAR (cl_prednudge)
EXTERN_CVAR (cl_predictpickup)
EXTERN_CVAR (cl_predictsectors)
EXTERN_CVAR (cl_predictweapons)
EXTERN_CVAR (cl_serverdownload)
// Demo Options
@ -335,7 +340,7 @@ menu_t OptionMenu = {
*=======================================*/
static menuitem_t ControlsItems[] = {
#ifdef _XBOX
#ifdef GCONSOLE
{ whitetext,"A to change, START to clear", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} },
#else
{ whitetext,"ENTER to change, BACKSPACE to clear", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} },
@ -516,14 +521,6 @@ static menuitem_t JoystickItems[] =
{ slider , "Turn Sensitivity" , {&joy_sensitivity}, {1.0}, {30.0}, {1.0}, {NULL} },
{ slider , "Alt. Turn Sensitivity" , {&joy_fastsensitivity}, {1.0}, {30.0}, {1.0}, {NULL} },
{ slider , "Joystick Deadzone" , {&joy_deadzone}, {0.0}, {0.75}, {0.05}, {NULL} },
#ifdef SDL12
{ redtext , " " , {NULL}, {0.0}, {0.0}, {0.0}, {NULL} },
{ whitetext , "Press ENTER to change" , {NULL}, {0.0}, {0.0}, {0.0}, {NULL} },
{ joyaxis , "Walk Analog Axis" , {&joy_forwardaxis}, {0.0}, {0.0}, {0.0}, {NULL} },
{ joyaxis , "Strafe Analog Axis" , {&joy_strafeaxis}, {0.0}, {0.0}, {0.0}, {NULL} },
{ joyaxis , "Turn Analog Axis" , {&joy_turnaxis}, {0.0}, {0.0}, {0.0}, {NULL} },
{ joyaxis , "Look Analog Axis" , {&joy_lookaxis}, {0.0}, {0.0}, {0.0}, {NULL} },
#endif
};
menu_t JoystickMenu = {
@ -646,7 +643,8 @@ static menuitem_t SoundItems[] = {
{ discrete , "Player Connect Alert" , {&cl_connectalert}, {2.0}, {0.0}, {0.0}, {OnOff} },
{ discrete , "Player Disconnect Alert" , {&cl_disconnectalert}, {2.0}, {0.0}, {0.0}, {OnOff} },
{ discrete , "Chat sounds" , {&cl_chatsounds}, {3.0}, {0.0}, {0.0}, {ChatSndType}},
};
{discrete , "Voting Sounds" , {&snd_votesfx}, {2.0}, {0.0}, {0.0}, {OnOff}},
};
menu_t AdvMidiMenu = {
"M_SOUND",
@ -703,7 +701,16 @@ static menuitem_t CompatItems[] ={
{svdiscrete, "BOOM actor/sector/line checks", {&co_boomphys}, {2.0}, {0.0}, {0.0}, {OnOff}},
{svdiscrete, "MBF movement and collision", {&co_mbfphys}, {2.0}, {0.0}, {0.0}, {OnOff}},
{svdiscrete, "ZDOOM 1.23 physics", {&co_zdoomphys}, {2.0}, {0.0}, {0.0}, {OnOff}},
{svdiscrete, "ZDOOM 1.23 ammo checks", {&co_zdoomammo}, {2.0}, {0.0}, {0.0}, {OnOff}},
{svdiscrete, "ZDOOM 1.23 ammo checks", {&co_zdoomammo}, {2.0}, {0.0}, {0.0}, {OnOff}},
{svdiscrete, "MBF Monster target selection",{&co_pursuit}, {2.0}, {0.0}, {0.0}, {OnOff}},
{svdiscrete, "Monsters help friends (MBF)",{&co_helpfriends}, {2.0}, {0.0}, {0.0}, {OnOff}},
{svdiscrete, "Monsters strafe (MBF)",{&co_monsterbacking}, {2.0}, {0.0}, {0.0}, {OnOff}},
{svdiscrete, "Monster wind/friction (MBF)",{&co_monsterfriction}, {2.0}, {0.0}, {0.0}, {OnOff}},
{svdiscrete, "Monsters avoid crushers (MBF)",{&co_avoidhazards}, {2.0}, {0.0}, {0.0}, {OnOff}},
{svdiscrete, "Monsters climb (MBF)",{&co_monstersclimbsteep}, {2.0}, {0.0}, {0.0}, {OnOff}},
{svdiscrete, "Monsters stay on lifts (MBF)",{&co_staylift}, {2.0}, {0.0}, {0.0}, {OnOff}},
{svdiscrete, "Friends can drop off (MBF)",{&co_friend_ledgejumping}, {2.0}, {0.0}, {0.0}, {OnOff}},
{slider, "Friend distance (MBF)", {&co_friend_distance}, {0.0}, {2048.0}, {64.0}, {NULL}},
{redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL}},
{yellowtext, "Sound", {NULL}, {0.0}, {0.0}, {0.0}, {NULL}},
{svdiscrete, "Fix silent west spawns", {&co_nosilentspawns}, {2.0}, {0.0}, {0.0}, {OnOff}},
@ -729,21 +736,9 @@ menu_t CompatMenu = {
*
*=======================================*/
static value_t PredictSectors[] = {
{ 0.0, "None" },
{ 1.0, "All" },
{ 2.0, "Only Mine" }
};
static menuitem_t NetworkItems[] = {
{ redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} },
{ yellowtext, "Adjust Network Settings", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} },
{ slider, "Interpolation time", {&cl_interp}, {0.0}, {4.0}, {1.0}, {NULL} },
{ slider, "Smooth collisions", {&cl_prednudge}, {1.0}, {0.1}, {-0.1}, {NULL} },
{ discrete, "Predict weapon pickups", {&cl_predictpickup},{2.0}, {0.0}, {0.0}, {OnOff} },
{ discrete, "Predict sector actions", {&cl_predictsectors},{3.0}, {0.0}, {0.0}, {PredictSectors} },
{ discrete, "Predict weapon effects", {&cl_predictweapons},{2.0}, {0.0}, {0.0}, {OnOff} },
{ redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} },
{ yellowtext, "Wad Download Settings", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} },
{ discrete, "Download From Internet", {&cl_serverdownload}, {2.0}, {0.0}, {0.0}, {OnOff} },
{ redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} },
@ -857,6 +852,7 @@ EXTERN_CVAR (r_painintensity)
EXTERN_CVAR (cl_movebob)
EXTERN_CVAR (cl_centerbobonfire)
EXTERN_CVAR (cl_showspawns)
EXTERN_CVAR (cl_showfriends)
EXTERN_CVAR (hud_show_scoreboard_ondeath)
EXTERN_CVAR (hud_demobar)
EXTERN_CVAR(hud_targetnames)
@ -932,6 +928,7 @@ static menuitem_t VideoItems[] = {
{ discrete, "Linear Skies", {&r_linearsky}, {2.0}, {0.0}, {0.0}, {OnOff} },
{ discrete, "Invuln changes skies", {&r_skypalette}, {2.0}, {0.0}, {0.0}, {OnOff} },
{ discrete, "Use softer invuln effect", {&r_softinvulneffect}, {2.0}, {0.0}, {0.0}, {OnOff} },
{ discrete, "Heart effect on friendlies", {&cl_showfriends}, {2.0}, {0.0}, {0.0}, {OnOff} },
{ discrete, "Screen wipe style", {&r_wipetype}, {4.0}, {0.0}, {0.0}, {Wipes} },
{ discrete, "Multiplayer Intermissions",{&wi_oldintermission}, {2.0}, {0.0}, {0.0}, {DoomOrOdamex} },
{ discrete, "Show loading disk icon", {&r_loadicon}, {2.0}, {0.0}, {0.0}, {OnOff} },
@ -1226,7 +1223,7 @@ void M_RestoreVideoMode()
static value_t Depths[22];
#ifdef _XBOX
#ifdef GCONSOLE
static const char VMEnterText[] = "Press A to set mode";
static const char VMTestText[] = "Press X to test mode for 5 seconds";
#else
@ -1507,12 +1504,12 @@ void M_ChangeMessages (void)
{
if (show_messages)
{
Printf (128, "%s\n", GStrings(MSGOFF));
PrintFmt(128, "{}\n", GStrings(MSGOFF));
show_messages.Set (0.0f);
}
else
{
Printf (128, "%s\n", GStrings(MSGON));
PrintFmt(128, "{}\n", GStrings(MSGON));
show_messages.Set (1.0f);
}
}
@ -1964,17 +1961,17 @@ void M_OptResponder (event_t *ev)
// to make sure we get the one that is intended -- Hyper_Eye
if( (ev->data3 > (SHRT_MAX / 2)) || (ev->data3 < (SHRT_MIN / 2)) )
{
if( (ev->data2 == (int)joy_forwardaxis) &&
joy_forwardaxis.name() != item->a.cvar->name() )
if ((ev->data2 == joy_forwardaxis.asInt()) &&
joy_forwardaxis.name() != item->a.cvar->name())
joy_forwardaxis.Set(item->a.cvar->value());
else if( (ev->data2 == (int)joy_strafeaxis) &&
joy_strafeaxis.name() != item->a.cvar->name() )
else if ((ev->data2 == joy_strafeaxis.asInt()) &&
joy_strafeaxis.name() != item->a.cvar->name())
joy_strafeaxis.Set(item->a.cvar->value());
else if( (ev->data2 == (int)joy_turnaxis) &&
joy_turnaxis.name() != item->a.cvar->name() )
else if ((ev->data2 == joy_turnaxis.asInt()) &&
joy_turnaxis.name() != item->a.cvar->name())
joy_turnaxis.Set(item->a.cvar->value());
else if( (ev->data2 == (int)joy_lookaxis) &&
joy_lookaxis.name() != item->a.cvar->name() )
else if ((ev->data2 == joy_lookaxis.asInt()) &&
joy_lookaxis.name() != item->a.cvar->name())
joy_lookaxis.Set(item->a.cvar->value());
item->a.cvar->Set(ev->data2);
@ -2490,7 +2487,7 @@ void M_OptResponder (event_t *ev)
}
else
{
#ifdef _XBOX
#ifdef GCONSOLE
if (ev->data3 == 't' || ev->data1 == OKEY_JOY3)
#else
if (ev->data3 == 't')

View file

@ -465,11 +465,11 @@ bool OTransfer::tick()
return false;
}
Printf("Saved to fallback location \"%s\".\n", fallback);
PrintFmt("Saved to fallback location \"{}\".\n", fallback);
}
else
{
Printf("Saved to location \"%s\".\n", m_filename);
PrintFmt("Saved to location \"{}\".\n", m_filename);
}
m_shouldCheckAgain = false;

View file

@ -68,6 +68,7 @@ const fixed_t NEARCLIP = 2*FRACUNIT;
drawseg_t* ds_p;
drawseg_t* drawsegs;
drawseg_t* firstdrawseg;
unsigned maxdrawsegs;
// CPhipps -
@ -93,8 +94,10 @@ void R_ReallocDrawSegs(void)
if (ds_p == drawsegs+maxdrawsegs) // killough 1/98 -- fix 2s line HOM
{
unsigned pos = ds_p - drawsegs; // jff 8/9/98 fix from ZDOOM1.14a
unsigned firstofs = firstdrawseg - drawsegs;
unsigned newmax = maxdrawsegs ? maxdrawsegs*2 : 128; // killough
drawsegs = (drawseg_t*)M_Realloc(drawsegs, newmax*sizeof(*drawsegs));
firstdrawseg = drawsegs + firstofs;
ds_p = drawsegs + pos; // jff 8/9/98 fix from ZDOOM1.14a
maxdrawsegs = newmax;
DPrintFmt("MaxDrawSegs increased to {}\n", maxdrawsegs);
@ -106,6 +109,11 @@ void R_ReallocDrawSegs(void)
//
void R_ClearDrawSegs(void)
{
if (drawsegs == NULL)
{
maxdrawsegs = 256;
firstdrawseg = drawsegs = (drawseg_t*)Malloc(maxdrawsegs * sizeof(drawseg_t));
}
ds_p = drawsegs;
}
@ -687,7 +695,8 @@ void R_Subsector (int num)
frontsector->ceiling_yoffs + frontsector->base_ceiling_yoffs,
frontsector->ceiling_xscale,
frontsector->ceiling_yscale,
frontsector->ceiling_angle + frontsector->base_ceiling_angle
frontsector->ceiling_angle + frontsector->base_ceiling_angle,
frontsector->Skybox
) : NULL;
// killough 3/7/98: Add (x,y) offsets to flats, add deep water check
@ -706,7 +715,8 @@ void R_Subsector (int num)
frontsector->floor_yoffs + frontsector->base_floor_yoffs,
frontsector->floor_xscale,
frontsector->floor_yscale,
frontsector->floor_angle + frontsector->base_floor_angle
frontsector->floor_angle + frontsector->base_floor_angle,
frontsector->Skybox
) : NULL;
// [RH] set foggy flag

View file

@ -229,7 +229,7 @@ static void R_BuildFontTranslation(int color_num, argb_t start_color, argb_t end
palindex_t* dest = (palindex_t*)Ranges + color_num * 256;
if (gamemode == retail_chex)
if (IsChexMission(gamemission))
{
for (int index = 0; index < chexstart_index; index++)
dest[index] = index;
@ -258,7 +258,7 @@ static void R_BuildFontTranslation(int color_num, argb_t start_color, argb_t end
int b_diff = end_color.getb() - start_color.getb();
int hacxtrack;
if (gamemode == retail_chex)
if (IsChexMission(gamemission))
{
for (palindex_t index = chexstart_index; index <= chexend_index; index++)
{
@ -399,6 +399,18 @@ void R_InitTranslationTables()
::bosstable[i] = V_BestColor(V_GetDefaultPalette()->basecolors, mul);
}
// Friend translation is a pink tint.
const argb_t ptop(0xff, 0x70, 0xB9);
for (size_t i = 0; i < ARRAY_LENGTH(::friendtable); i++)
{
const argb_t bot = V_GetDefaultPalette()->basecolors[i];
const argb_t mul(SoftLight(bot.getr(), ptop.getr()),
SoftLight(bot.getg(), ptop.getg()),
SoftLight(bot.getb(), ptop.getb()));
::friendtable[i] = V_BestColor(V_GetDefaultPalette()->basecolors, mul);
}
translationtablesmem = new byte[256*(MAXPLAYERS+3+22)+255]; // denis - fixme - magic numbers?
// [Toke - fix13]
@ -618,7 +630,7 @@ static forceinline void R_FillColumnGeneric(PIXEL_T* dest, const drawcolumn_t& d
#ifdef RANGECHECK
if (drawcolumn.x < 0 || drawcolumn.x >= viewwidth || drawcolumn.yl < 0 || drawcolumn.yh >= viewheight)
{
Printf (PRINT_HIGH, "R_FillColumn: %i to %i at %i\n", drawcolumn.yl, drawcolumn.yh, drawcolumn.x);
PrintFmt(PRINT_HIGH, "R_FillColumn: {} to {} at {}\n", drawcolumn.yl, drawcolumn.yh, drawcolumn.x);
return;
}
#endif
@ -657,7 +669,7 @@ static forceinline void R_DrawColumnGeneric(PIXEL_T* dest, const drawcolumn_t& d
#ifdef RANGECHECK
if (drawcolumn.x < 0 || drawcolumn.x >= viewwidth || drawcolumn.yl < 0 || drawcolumn.yh >= viewheight)
{
Printf (PRINT_HIGH, "R_DrawColumn: %i to %i at %i\n", drawcolumn.yl, drawcolumn.yh, drawcolumn.x);
PrintFmt(PRINT_HIGH, "R_DrawColumn: {} to {} at {}\n", drawcolumn.yl, drawcolumn.yh, drawcolumn.x);
return;
}
#endif
@ -765,7 +777,7 @@ static forceinline void R_FillSpanGeneric(PIXEL_T* dest, const drawspan_t& draws
if (drawspan.x2 < drawspan.x1 || drawspan.x1 < 0 || drawspan.x2 >= viewwidth ||
drawspan.y >= viewheight || drawspan.y < 0)
{
Printf(PRINT_HIGH, "R_FillSpan: %i to %i at %i", drawspan.x1, drawspan.x2, drawspan.y);
PrintFmt(PRINT_HIGH, "R_FillSpan: {} to {} at {}", drawspan.x1, drawspan.x2, drawspan.y);
return;
}
#endif
@ -798,7 +810,7 @@ static forceinline void R_DrawLevelSpanGeneric(PIXEL_T* dest, const drawspan_t&
if (drawspan.x2 < drawspan.x1 || drawspan.x1 < 0 || drawspan.x2 >= viewwidth ||
drawspan.y >= viewheight || drawspan.y < 0)
{
Printf(PRINT_HIGH, "R_DrawLevelSpan: %i to %i at %i", drawspan.x1, drawspan.x2, drawspan.y);
PrintFmt(PRINT_HIGH, "R_DrawLevelSpan: {} to {} at {}", drawspan.x1, drawspan.x2, drawspan.y);
return;
}
#endif
@ -851,7 +863,7 @@ static forceinline void R_DrawSlopedSpanGeneric(PIXEL_T* dest, const drawspan_t&
if (drawspan.x2 < drawspan.x1 || drawspan.x1 < 0 || drawspan.x2 >= viewwidth ||
drawspan.y >= viewheight || drawspan.y < 0)
{
Printf(PRINT_HIGH, "R_DrawSlopedSpan: %i to %i at %i", drawspan.x1, drawspan.x2, drawspan.y);
PrintFmt(PRINT_HIGH, "R_DrawSlopedSpan: {} to {} at {}", drawspan.x1, drawspan.x2, drawspan.y);
return;
}
#endif
@ -1761,7 +1773,7 @@ static std::string get_optimization_name_list(const bool includeNone)
static void print_optimizations()
{
Printf(PRINT_HIGH, "r_optimize detected \"%s\"\n", get_optimization_name_list(false));
PrintFmt(PRINT_HIGH, "r_optimize detected \"{}\"\n", get_optimization_name_list(false));
}
static bool detect_optimizations()
@ -1826,8 +1838,8 @@ CVAR_FUNC_IMPL(r_optimize)
optimize_kind = optimizations_available.back();
else
{
Printf(PRINT_HIGH, "Invalid value for r_optimize. Availible options are \"%s, detect\"\n",
get_optimization_name_list(true));
PrintFmt(PRINT_HIGH, "Invalid value for r_optimize. Availible options are \"{}, detect\"\n",
get_optimization_name_list(true));
// Restore the original setting:
var.Set(get_optimization_name(optimize_kind));
@ -1839,7 +1851,7 @@ CVAR_FUNC_IMPL(r_optimize)
{
// update the cvar string
// this will trigger the callback to run a second time
Printf(PRINT_HIGH, "r_optimize set to \"%s\" based on availability\n", optimize_name);
PrintFmt(PRINT_HIGH, "r_optimize set to \"{}\" based on availability\n", optimize_name);
var.Set(optimize_name);
}
else

View file

@ -61,7 +61,7 @@ void R_DrawSpanD_SSE2 (void)
if (dspan.x2 < dspan.x1 || dspan.x1 < 0 || dspan.x2 >= viewwidth ||
dspan.y >= viewheight || dspan.y < 0)
{
Printf(PRINT_HIGH, "R_DrawLevelSpan: %i to %i at %i", dspan.x1, dspan.x2, dspan.y);
PrintFmt(PRINT_HIGH, "R_DrawLevelSpan: {} to {} at {}", dspan.x1, dspan.x2, dspan.y);
return;
}
#endif

View file

@ -232,7 +232,7 @@ void OInterpolation::ticGameInterpolation()
// Functions that assist with the interpolation of certain game objects
void OInterpolation::interpolateCeilings(fixed_t amount)
{
for (const auto [old_value, secnum] : prev_ceilingheight)
for (const auto& [old_value, secnum] : prev_ceilingheight)
{
sector_t* sector = &sectors[secnum];
@ -265,7 +265,7 @@ void OInterpolation::interpolateCeilings(fixed_t amount)
void OInterpolation::interpolateFloors(fixed_t amount)
{
for (const auto [old_value, secnum] : prev_floorheight)
for (const auto& [old_value, secnum] : prev_floorheight)
{
sector_t* sector = &sectors[secnum];
@ -382,7 +382,7 @@ void OInterpolation::beginGameInterpolation(fixed_t amount)
void OInterpolation::restoreCeilings(void)
{
// Ceiling heights
for (const auto [height, secnum] : saved_ceilingheight)
for (const auto& [height, secnum] : saved_ceilingheight)
{
sector_t* sector = &sectors[secnum];
P_SetCeilingHeight(sector, height);

View file

@ -32,7 +32,6 @@
#include "m_fixed.h"
#include "r_defs.h"
#include <map>
typedef std::pair<fixed_t, unsigned int> fixed_uint_pair;
typedef std::pair<std::pair<fixed_t, fixed_t>, unsigned int> fixed_fixed_uint_pair;

View file

@ -638,6 +638,20 @@ subsector_t *R_PointInSubsector (fixed_t x, fixed_t y)
return &subsectors[nodenum & ~NF_SUBSECTOR];
}
//
//
// R_SetViewAngle
//
//
void R_SetViewAngle(angle_t ang)
{
viewangle = ang;
viewsin = finesine[ang >> ANGLETOFINESHIFT];
viewcos = finecosine[ang >> ANGLETOFINESHIFT];
}
//
// R_ViewShear
//
@ -984,7 +998,7 @@ void R_RenderPlayerView(player_t* player)
R_ClearClipSegs();
R_ClearDrawSegs();
R_ClearOpenings();
R_ClearPlanes();
R_ClearPlanes(true);
R_ClearSprites();
R_ResetDrawFuncs();
@ -1019,7 +1033,7 @@ void R_RenderPlayerView(player_t* player)
R_RenderBSPNode(numnodes - 1); // The head node is the last node output.
R_DrawPlanes();
R_DrawSkyBoxes();
R_DrawMasked();
// NOTE(jsd): Full-screen status color blending:

View file

@ -38,6 +38,7 @@
#include "z_zone.h"
#include "w_wad.h"
#include "m_mempool.h"
#include "p_local.h"
#include "r_local.h"
@ -59,10 +60,12 @@ planefunction_t ceilingfunc;
static constexpr float flatwidth = 64.0f;
static constexpr float flatheight = 64.0f;
static visplane_t *visplanes[MAXVISPLANES]; // killough
static visplane_t *visplanes[MAXVISPLANES + 1]; // killough
static visplane_t *freetail; // killough
static visplane_t **freehead = &freetail; // killough
static bool r_InSkyBox;
visplane_t *floorplane;
visplane_t *ceilingplane;
visplane_t *skyplane;
@ -95,6 +98,7 @@ int *spanstart;
extern fixed_t FocalLengthX, FocalLengthY;
extern float xfoc, yfoc;
extern float focratio, ifocratio;
extern Pool<int> sprclip_pool;
int* planezlight;
float plight, shade;
@ -253,15 +257,18 @@ void R_MapLevelPlane(int y, int x1, int x2)
// R_ClearPlanes
// At begining of frame.
//
void R_ClearPlanes (void)
void R_ClearPlanes(bool fullclear)
{
// opening / clipping determination
memcpy(floorclip, floorclipinitial, viewwidth * sizeof(*floorclip));
memcpy(ceilingclip, ceilingclipinitial, viewwidth * sizeof(*ceilingclip));
for (int i = 0; i < MAXVISPLANES; i++) // new code -- killough
for (*freehead = visplanes[i], visplanes[i] = NULL; *freehead; )
freehead = &(*freehead)->next;
if (fullclear)
{
// opening / clipping determination
memcpy(floorclip, floorclipinitial, viewwidth * sizeof(*floorclip));
memcpy(ceilingclip, ceilingclipinitial, viewwidth * sizeof(*ceilingclip));
}
}
//
@ -292,31 +299,50 @@ static visplane_t *new_visplane(unsigned hash)
//
// killough 2/28/98: Add offsets
//
visplane_t *R_FindPlane (plane_t secplane, int picnum, int lightlevel,
visplane_t *R_FindPlane (const plane_t &secplane, int picnum, int lightlevel,
fixed_t xoffs, fixed_t yoffs,
fixed_t xscale, fixed_t yscale, angle_t angle)
fixed_t xscale, fixed_t yscale, angle_t angle,
AActor::AActorPtr skybox)
{
visplane_t *check;
unsigned hash; // killough
bool isskybox;
if (R_IsSkyFlat(picnum) || picnum & PL_SKYFLAT) // killough 10/98
lightlevel = 0; // most skies map together
{
lightlevel = 0; // most skies map together
isskybox = (picnum == skyflatnum) && (skybox != NULL) && !r_InSkyBox;
}
else
{
isskybox = false;
}
// New visplane algorithm uses hash table -- killough
hash = visplane_hash (picnum, lightlevel, secplane);
hash = isskybox ? MAXVISPLANES : visplane_hash(picnum, lightlevel, secplane);
for (check = visplanes[hash]; check; check = check->next) // killough
if (P_IdenticalPlanes(&secplane, &check->secplane) &&
picnum == check->picnum &&
lightlevel == check->lightlevel &&
xoffs == check->xoffs && // killough 2/28/98: Add offset checks
yoffs == check->yoffs &&
basecolormap == check->colormap && // [RH] Add colormap check
xscale == check->xscale &&
yscale == check->yscale &&
angle == check->angle
)
return check;
for (check = visplanes[hash]; check; check = check->next) // killough
{
if (isskybox)
{
if (skybox == check->skybox)
{
return check;
}
}
else if (P_IdenticalPlanes(&secplane, &check->secplane) &&
picnum == check->picnum &&
lightlevel == check->lightlevel &&
xoffs == check->xoffs && // killough 2/28/98: Add offset checks
yoffs == check->yoffs &&
basecolormap == check->colormap && // [RH] Add colormap check
xscale == check->xscale &&
yscale == check->yscale &&
angle == check->angle)
{
return check;
}
}
check = new_visplane (hash); // killough
@ -329,6 +355,7 @@ visplane_t *R_FindPlane (plane_t secplane, int picnum, int lightlevel,
check->yscale = yscale;
check->angle = angle;
check->colormap = basecolormap; // [RH] Save colormap
check->skybox = skybox;
check->minx = viewwidth; // Was SCREENWIDTH -- killough 11/98
check->maxx = -1;
@ -382,7 +409,16 @@ visplane_t* R_CheckPlane(visplane_t* pl, int start, int stop)
else
{
// make a new visplane
unsigned hash = visplane_hash (pl->picnum, pl->lightlevel, pl->secplane);
unsigned hash;
if (pl->picnum == skyflatnum && pl->skybox != NULL && !r_InSkyBox)
{
hash = MAXVISPLANES;
}
else
{
hash = visplane_hash(pl->picnum, pl->lightlevel, pl->secplane);
}
visplane_t *new_pl = new_visplane (hash);
new_pl->secplane = pl->secplane;
@ -394,6 +430,7 @@ visplane_t* R_CheckPlane(visplane_t* pl, int start, int stop)
new_pl->yscale = pl->yscale;
new_pl->angle = pl->angle;
new_pl->colormap = pl->colormap; // [RH] Copy colormap
new_pl->skybox = pl->skybox;
pl = new_pl;
pl->minx = start;
pl->maxx = stop;
@ -600,6 +637,7 @@ void R_DrawPlanes (void)
{
visplane_t *pl;
int i;
int vpcount;
R_ResetDrawFuncs();
@ -682,6 +720,124 @@ void R_DrawPlanes (void)
}
}
//==========================================================================
//
// R_DrawSkyBoxes
//
// Draws any recorded sky boxes and then frees them.
//
// The process:
// 1. Move the camera to coincide with the SkyViewpoint.
// 2. Clear out the old planes. (They have already been drawn.)
// 3. Clear a window out of the ClipSegs just large enough for the plane.
// 4. Pretend the existing vissprites and drawsegs aren't there.
// 5. Create a drawseg at 0 distance to clip sprites to the visplane. It
// doesn't need to be associated with a line in the map, since there
// will never be any sprites in front of it.
// 6. Render the BSP, then planes, then masked stuff.
// 7. Restore the previous vissprites and drawsegs.
// 8. Repeat for any other sky boxes.
// 9. Put the camera back where it was to begin with.
//
//==========================================================================
void R_DrawSkyBoxes()
{
if (visplanes[MAXVISPLANES] == NULL)
return;
int savedextralight = extralight;
fixed_t savedx = viewx;
fixed_t savedy = viewy;
fixed_t savedz = viewz;
angle_t savedangle = viewangle;
ptrdiff_t savedvissprite_p = vissprite_p - vissprites;
ptrdiff_t savedds_p = ds_p - drawsegs;
AActor* savedcamera = camera;
int i;
visplane_t* pl;
// Don't draw sky boxes inside sky boxes.
r_InSkyBox = true;
// Don't let gun flashes brighten the sky box
extralight = 0;
for (pl = visplanes[MAXVISPLANES]; pl != NULL; pl = pl->next)
{
if (pl->maxx < pl->minx)
continue;
AActor::AActorPtr sky = pl->skybox;
viewx = sky->x;
viewy = sky->y;
viewz = sky->z;
camera = sky;
R_SetViewAngle(savedangle + sky->angle);
validcount++; // Make sure we see all sprites
R_ClearPlanes(false);
R_ClearClipSegs();
// Set up ceiling/floor clip arrays for this visplane.
for (i = pl->minx; i <= pl->maxx; i++)
{
if (pl->top[i] == (unsigned int)viewheight)
{
ceilingclip[i] = viewheight;
floorclip[i] = -1;
}
else
{
ceilingclip[i] = pl->top[i];
floorclip[i] = pl->bottom[i];
}
}
// Create a drawseg to clip sprites to the sky plane.
R_ReallocDrawSegs();
ds_p->x1 = 0;
ds_p->x2 = viewwidth - 1;
ds_p->silhouette = SIL_BOTH;
ds_p->midposts = NULL;
ds_p->curline = NULL;
// [RK] Allocate full width clip arrays.
ds_p->sprbottomclip = sprclip_pool.alloc(viewwidth);
ds_p->sprtopclip = sprclip_pool.alloc(viewwidth);
// [RK] Copy visplane clip values into the arrays.
memcpy(ds_p->sprbottomclip, floorclip, viewwidth * sizeof(*ds_p->sprbottomclip));
memcpy(ds_p->sprtopclip, ceilingclip, viewwidth * sizeof(*ds_p->sprtopclip));
firstvissprite = vissprite_p;
firstdrawseg = ds_p++;
R_RenderBSPNode(numnodes - 1);
R_DrawPlanes();
R_DrawMasked();
firstvissprite = vissprites;
vissprite_p = vissprites + savedvissprite_p;
firstdrawseg = drawsegs;
ds_p = drawsegs + savedds_p;
}
camera = savedcamera;
viewx = savedx;
viewy = savedy;
viewz = savedz;
extralight = savedextralight;
R_SetViewAngle(savedangle);
r_InSkyBox = false;
for (*freehead = visplanes[MAXVISPLANES], visplanes[MAXVISPLANES] = NULL; *freehead;)
freehead = &(*freehead)->next;
}
//
// R_PlaneInitData
//

View file

@ -97,6 +97,7 @@ extern float yfoc;
static tallpost_t** masked_midposts;
EXTERN_CVAR(r_clipmaskedspecial)
//
// R_TexScaleX
@ -942,6 +943,9 @@ void R_StoreWallRange(int start, int stop)
// killough 4/17/98: draw floors if different light levels
|| backsector->floorlightsec != frontsector->floorlightsec
// [EB] check for special too for DSDA-compatibility on MBF21
|| (r_clipmaskedspecial && backsector->special != frontsector->special)
// [RH] Add checks for colormaps
|| backsector->colormap != frontsector->colormap

View file

@ -44,6 +44,7 @@ extern fixed_t freelookviewheight;
EXTERN_CVAR(sv_freelook)
EXTERN_CVAR(cl_mouselook)
EXTERN_CVAR(joy_freelook)
EXTERN_CVAR(r_skypalette)
EXTERN_CVAR(r_linearsky)
@ -292,8 +293,10 @@ void R_InitSkyMap()
if (fskyheight <= (128 << FRACBITS))
{
defaultskytexturemid = 200/2*FRACUNIT;
skystretch = (r_stretchsky == 1) || consoleplayer().spectator || (r_stretchsky == 2 && sv_freelook && cl_mouselook);
defaultskytexturemid = 200 / 2 * FRACUNIT;
skystretch = ((r_stretchsky != 0) && consoleplayer().spectator) ||
(r_stretchsky == 1) ||
(r_stretchsky == 2 && sv_freelook && (cl_mouselook || joy_freelook));
}
else
{

View file

@ -68,11 +68,12 @@ fixed_t bobx;
fixed_t boby;
#define MAX_SPRITE_FRAMES 29 // [RH] Macro-ized as in BOOM.
#define SPRITE_NEEDS_INFO MAXINT
#define SPRITE_NEEDS_INFO limits::MAXINT
EXTERN_CVAR (r_drawplayersprites)
EXTERN_CVAR (r_softinvulneffect)
EXTERN_CVAR (r_particles)
EXTERN_CVAR (r_thingsectorlight);
//
// INITIALIZATION FUNCTIONS
@ -88,7 +89,7 @@ extern int NumParticles;
extern int ActiveParticles;
extern int InactiveParticles;
extern particle_t *Particles;
TArray<WORD> ParticlesInSubsec;
std::vector<WORD> ParticlesInSubsec;
@ -106,7 +107,7 @@ int newvissprite;
//
void R_ClearSprites()
{
vissprite_p = vissprites;
vissprite_p = firstvissprite;
}
@ -116,11 +117,13 @@ void R_ClearSprites()
vissprite_t *R_NewVisSprite()
{
if (vissprite_p == lastvissprite) {
int firstvisspritenum = firstvissprite - vissprites;
int prevvisspritenum = vissprite_p - vissprites;
MaxVisSprites *= 2;
vissprites = (vissprite_t *)M_Realloc (vissprites, MaxVisSprites * sizeof(vissprite_t));
lastvissprite = &vissprites[MaxVisSprites];
firstvissprite = &vissprites[firstvisspritenum];
vissprite_p = &vissprites[prevvisspritenum];
DPrintFmt("MaxVisSprites increased to {}\n", MaxVisSprites);
}
@ -324,8 +327,8 @@ void R_DrawVisSprite (vissprite_t *vis, int x1, int x2)
#if 0
if ((colfrac - vis->xiscale) >> FRACBITS != end)
{
Printf(PRINT_WARNING, "Bad vissprite bounds check! (pw:%d ex:%d act:%d)\n",
patchWidth, end, colfrac >> FRACBITS);
PrintFmt(PRINT_WARNING, "Bad vissprite bounds check! (pw:{} ex:{} act:{})\n",
patchWidth, end, colfrac >> FRACBITS);
}
#endif
@ -451,7 +454,7 @@ static vissprite_t* R_GenerateVisSprite(const sector_t* sector, int fakeside,
return vis;
}
void R_DrawHitBox(AActor* thing)
void R_DrawHitBox(const AActor* thing)
{
v3fixed_t vertices[8];
static constexpr byte color = 0x80;
@ -521,10 +524,8 @@ void R_DrawHitBox(AActor* thing)
// R_ProjectSprite
// Generates a vissprite for a thing if it might be visible.
//
void R_ProjectSprite(AActor *thing, int fakeside)
void R_ProjectSprite(const AActor *thing, int fakeside)
{
spritedef_t* sprdef;
spriteframe_t* sprframe;
int lump;
unsigned int rot;
bool flip;
@ -563,25 +564,27 @@ void R_ProjectSprite(AActor *thing, int fakeside)
thingz = thing->z;
}
auto it = sprites.find(thing->sprite);
#ifdef RANGECHECK
if (static_cast<unsigned>(thing->sprite) >= static_cast<unsigned>(numsprites))
if (it == sprites.end())
{
DPrintFmt("R_ProjectSprite: invalid sprite number {}\n", thing->sprite);
DPrintFmt("R_ProjectSprite: thing ({}: {}): invalid sprite number {}\n on ", thing->type, thing->info->name, thing->sprite);
return;
}
#endif
sprdef = &sprites[thing->sprite];
const spritedef_t* sprdef = &it->second;
#ifdef RANGECHECK
if ( (thing->frame & FF_FRAMEMASK) >= sprdef->numframes )
{
DPrintFmt("R_ProjectSprite: invalid sprite frame {} : {}\n ", thing->sprite, thing->frame);
DPrintFmt("R_ProjectSprite: thing ({}: {}): invalid sprite frame {} : {}\n ", thing->type, thing->info->name, thing->sprite, thing->frame);
return;
}
#endif
sprframe = &sprdef->spriteframes[thing->frame & FF_FRAMEMASK];
const spriteframe_t* sprframe = &sprdef->spriteframes[thing->frame & FF_FRAMEMASK];
// decide which patch to use for sprite relative to player
if (sprframe->rotate)
@ -608,8 +611,15 @@ void R_ProjectSprite(AActor *thing, int fakeside)
flip = sprframe->flip[0];
}
if (lump == -1) {
char frame = (thing->frame & FF_FRAMEMASK) + 'A';
I_Error("Frame {} for sprite {} could not be found.", frame, sprnames[thing->sprite]);
}
if (sprframe->width[rot] == SPRITE_NEEDS_INFO)
{
R_CacheSprite (sprdef); // [RH] speeds up game startup time
}
sector_t* sector = thing->subsector->sector;
fixed_t topoffs = sprframe->topoffset[rot];
@ -680,7 +690,8 @@ void R_AddSprites (sector_t *sec, int lightlevel, int fakeside)
// Well, now it will be done.
sec->validcount = validcount;
int lightnum = (lightlevel >> LIGHTSEGSHIFT) + (foggy ? 0 : extralight);
int lightnum = r_thingsectorlight ? lightlevel : sec->lightlevel;
lightnum = (lightnum >> LIGHTSEGSHIFT) + (foggy ? 0 : extralight);
if (lightnum < 0)
spritelights = scalelight[0];
@ -690,7 +701,7 @@ void R_AddSprites (sector_t *sec, int lightlevel, int fakeside)
spritelights = scalelight[lightnum];
// Handle all things in sector.
for (AActor* thing = sec->thinglist; thing; thing = thing->snext)
for (const AActor* thing = sec->thinglist; thing; thing = thing->snext)
{
R_ProjectSprite (thing, fakeside);
}
@ -702,65 +713,58 @@ void R_AddSprites (sector_t *sec, int lightlevel, int fakeside)
//
void R_DrawPSprite(pspdef_t* psp, unsigned flags)
{
fixed_t tx;
int x1;
int x2;
spritedef_t* sprdef;
spriteframe_t* sprframe;
int lump;
bool flip;
vissprite_t* vis;
vissprite_t avis;
// decide which patch to use
auto it = sprites.find(psp->state->sprite);
#ifdef RANGECHECK
if ( (unsigned)psp->state->sprite >= (unsigned)numsprites) {
if (it == sprites.end()) {
DPrintFmt("R_DrawPSprite: invalid sprite number {}\n", psp->state->sprite);
return;
}
#endif
sprdef = &sprites[psp->state->sprite];
const spritedef_t* sprdef = &it->second;
#ifdef RANGECHECK
if ( (psp->state->frame & FF_FRAMEMASK) >= sprdef->numframes) {
DPrintFmt("R_DrawPSprite: invalid sprite frame {} : {}\n", psp->state->sprite, psp->state->frame);
return;
}
#endif
sprframe = &sprdef->spriteframes[ psp->state->frame & FF_FRAMEMASK ];
const spriteframe_t* sprframe = &sprdef->spriteframes[ psp->state->frame & FF_FRAMEMASK ];
lump = sprframe->lump[0];
flip = sprframe->flip[0];
const int32_t lump = sprframe->lump[0];
const bool flip = sprframe->flip[0];
if (sprframe->width[0] == SPRITE_NEEDS_INFO)
R_CacheSprite (sprdef); // [RH] speeds up game startup time
// calculate edges of the shape
tx = bobx - ((320 / 2) << FRACBITS);
fixed_t tx = bobx - ((320 / 2) << FRACBITS);
tx -= sprframe->offset[0]; // [RH] Moved out of spriteoffset[]
x1 = (centerxfrac + FixedMul (tx, pspritexscale)) >>FRACBITS;
const int32_t x1 = (centerxfrac + FixedMul (tx, pspritexscale)) >>FRACBITS;
// off the right side
if (x1 > viewwidth)
return;
tx += sprframe->width[0]; // [RH] Moved out of spritewidth[]
x2 = ((centerxfrac + FixedMul (tx, pspritexscale)) >>FRACBITS) - 1;
const int32_t x2 = ((centerxfrac + FixedMul (tx, pspritexscale)) >>FRACBITS) - 1;
// off the left side
if (x2 < 0)
return;
// store information in a vissprite
vis = &avis;
vissprite_t* vis = &avis;
vis->mobjflags = flags;
vis->statusflags = camera->player && camera->player->mo ? camera->player->mo->statusflags : 0;
// [RH] +0x6000 helps it meet the screen bottom
// at higher resolutions while still being in
// the right spot at 320x200.
// denis - bump to 0x9000
#define WEAPONTWEAK (0x9000)
// [RH] +0x6000 helps it meet the screen bottom
// at higher resolutions while still being in
// the right spot at 320x200.
// denis - bump to 0x9000
static constexpr fixed_t WEAPONTWEAK = 0x9000;
vis->texturemid = (BASEYCENTER << FRACBITS) + FRACUNIT / 2 -
(boby + WEAPONTWEAK - sprframe->topoffset[0]); // [RH] Moved out of spritetopoffset[]
@ -924,20 +928,22 @@ static int STACK_ARGS sv_compare(const void *arg1, const void *arg2)
void R_SortVisSprites()
{
vsprcount = vissprite_p - vissprites;
vsprcount = vissprite_p - firstvissprite;
if (!vsprcount)
return;
if (spritesorter_size < MaxVisSprites)
{
delete [] spritesorter;
if (spritesorter != NULL)
delete [] spritesorter;
spritesorter = new vissprite_t*[MaxVisSprites];
spritesorter_size = MaxVisSprites;
}
for (int i = 0; i < vsprcount; i++)
spritesorter[i] = vissprites + i;
vissprite_t* spr = firstvissprite;
for (int i = 0; i < vsprcount; i++, spr++)
spritesorter[i] = spr;
qsort(spritesorter, vsprcount, sizeof(vissprite_t *), sv_compare);
}
@ -1021,7 +1027,7 @@ void R_DrawSprite (vissprite_t *spr)
// (pointer check was originally nonportable
// and buggy, by going past LEFT end of array):
for (ds = ds_p ; ds-- > drawsegs ; ) // new -- killough
for (ds = ds_p ; ds-- > firstdrawseg ; ) // new -- killough
{
// determine if the drawseg obscures the sprite
if (ds->x1 > spr->x2 || ds->x2 < spr->x1 ||
@ -1038,8 +1044,8 @@ void R_DrawSprite (vissprite_t *spr)
segscale2 = MIN<int>(ds->scale1, ds->scale2);
// check if the seg is in front of the sprite
if (segscale1 < spr->yscale ||
(segscale2 < spr->yscale && !R_PointOnSegSide(spr->gx, spr->gy, ds->curline)))
if (!(!ds->curline) && (segscale1 < spr->yscale ||
(segscale2 < spr->yscale && !R_PointOnSegSide(spr->gx, spr->gy, ds->curline))))
{
// masked mid texture?
if (ds->midposts)
@ -1084,8 +1090,10 @@ void R_DrawMasked (void)
R_SortVisSprites ();
while (vsprcount > 0)
R_DrawSprite(spritesorter[--vsprcount]);
for (int i = vsprcount; i > 0; i--)
{
R_DrawSprite(spritesorter[i-1]);
}
// render any remaining masked mid textures
@ -1095,7 +1103,7 @@ void R_DrawMasked (void)
// for (ds=ds_p-1 ; ds >= drawsegs ; ds--) old buggy code
for (ds=ds_p ; ds-- > drawsegs ; ) // new -- killough
for (ds=ds_p ; ds-- > firstdrawseg ; ) // new -- killough
if (ds->midposts)
R_RenderMaskedSegRange(ds, ds->x1, ds->x2);
@ -1136,12 +1144,8 @@ void R_ClearParticles (void)
void R_FindParticleSubsectors ()
{
if (ParticlesInSubsec.Size() < (size_t)numsubsectors)
ParticlesInSubsec.Reserve(numsubsectors - ParticlesInSubsec.Size());
// fill the buffer with NO_PARTICLE
for (int i = 0; i < numsubsectors; i++)
ParticlesInSubsec[i] = NO_PARTICLE;
ParticlesInSubsec.assign(numsubsectors, NO_PARTICLE);
if (!r_particles)
return;
@ -1164,24 +1168,44 @@ void R_ProjectParticle (particle_t *particle, const sector_t *sector, int fakesi
fixed_t x = particle->x;
fixed_t y = particle->y;
fixed_t z = particle->z;
fixed_t height = particle->size*(FRACUNIT/4);
fixed_t width = particle->size*(FRACUNIT/4);
fixed_t height = particle->size * (FRACUNIT / 4);
fixed_t width = particle->size * (FRACUNIT / 4);
fixed_t topoffs = height;
fixed_t sideoffs = width >> 1;
if (particle->sprite != NO_PARTICLE)
{
patch_t* patch = W_CachePatch(particle->sprite);
height = patch->height() << FRACBITS;
width = patch->width() << FRACBITS;
topoffs = patch->topoffset();
sideoffs = patch->leftoffset();
}
vissprite_t* vis = R_GenerateVisSprite(sector, fakeside, x, y, z, height, width, topoffs, sideoffs, false);
if (vis == NULL)
return;
vis->translation = translationref_t();
vis->startfrac = particle->color;
vis->patch = NO_PARTICLE;
vis->mobjflags = particle->trans;
vis->translucency = 65535;
vis->statusflags = 0;
vis->mo = NULL;
vis->spectator = false;
if (particle->sprite == NO_PARTICLE)
{
vis->startfrac = particle->color;
vis->patch = NO_PARTICLE;
vis->mobjflags = particle->trans;
}
else
{
vis->patch = particle->sprite;
vis->translucency = (particle->trans + 1) << 8;
vis->mobjflags = 0;
}
// get light level
if (fixedcolormap.isValid())
{

View file

@ -46,6 +46,7 @@
#include "m_fileio.h"
#include "gi.h"
#include "oscanner.h"
#include "g_musinfo.h"
#define NORM_PITCH 128
#define NORM_PRIORITY 64
@ -56,8 +57,8 @@ static constexpr fixed_t S_STEREO_SWING = 96 * FRACUNIT;
struct channel_t
{
public:
fixed_t* pt; // origin of sound
fixed_t x, y; // origin if pt is NULL
const fixed_t* pt; // origin of sound
fixed_t x, y; // origin if pt is nullptr
sfxinfo_t* sfxinfo; // sound information (if null, channel avail.)
int handle; // handle of the sound being played
int sound_id;
@ -73,9 +74,9 @@ public:
void clear()
{
pt = NULL;
pt = nullptr;
x = y = 0;
sfxinfo = NULL;
sfxinfo = nullptr;
handle = -1;
sound_id = -1;
entchannel = CHAN_VOICE;
@ -84,7 +85,7 @@ public:
dist = 0;
initial_volume = 0.0f;
volume = 0.0f;
priority = MININT;
priority = limits::MININT;
loop = false;
start_time = 0;
}
@ -168,7 +169,7 @@ void S_NoiseDebug()
if (Channel[i].sfxinfo)
{
char temp[16];
fixed_t *origin = Channel[i].pt;
const fixed_t *origin = Channel[i].pt;
if (Channel[i].attenuation == ATTN_NONE && listenplayer().camera)
{
@ -186,7 +187,7 @@ void S_NoiseDebug()
oy = Channel[i].y;
}
const int color = Channel[i].loop ? CR_BROWN : CR_GREY;
M_StringCopy(temp, lumpinfo[Channel[i].sfxinfo->lumpnum].name, 9);
M_StringCopy(temp, lumpinfo[Channel[i].sfxinfo->lumpnum].name.c_str(), 9);
screen->DrawText (color, 0, y, temp);
snprintf (temp, 16, "%d", ox / FRACUNIT);
screen->DrawText (color, 70, y, temp);
@ -277,8 +278,8 @@ void S_Init(float sfxVolume, float musicVolume)
*/
void S_Deinit()
{
::SoundCurve = NULL;
::Channel = NULL;
::SoundCurve = nullptr;
::Channel = nullptr;
}
//
@ -357,7 +358,7 @@ int S_GetChannel(sfxinfo_t* sfxinfo, float volume, int priority, unsigned max_in
fixed_t dist, int channel)
{
// not a valid sound
if (::Channel == NULL || sfxinfo == NULL)
if (::Channel == nullptr || sfxinfo == nullptr)
return -1;
// Sort the sound channels by descending priority levels
@ -387,7 +388,7 @@ int S_GetChannel(sfxinfo_t* sfxinfo, float volume, int priority, unsigned max_in
// try to find the first empty channel
for (size_t i = 0; i < numChannels; i++)
if (Channel[i].sfxinfo == NULL)
if (Channel[i].sfxinfo == nullptr)
return i;
// No empty channels and this is an ambient sound?
@ -608,7 +609,7 @@ static size_t ResolveSound(size_t soundid)
// joek - choco's S_StartSoundAtVolume with some zdoom code
// a bit of a whore of a funtion but she works ok
//
static void S_StartSound(fixed_t* pt, fixed_t x, fixed_t y, int channel,
static void S_StartSound(const fixed_t* pt, fixed_t x, fixed_t y, int channel,
int sfx_id, float volume, int attenuation, bool looping,
float dist_scale = 0.0f)
{
@ -652,9 +653,9 @@ static void S_StartSound(fixed_t* pt, fixed_t x, fixed_t y, int channel,
if (pt == (fixed_t *)(~0))
{
pt = NULL;
pt = nullptr;
}
else if (pt != NULL)
else if (pt != nullptr)
{
x = pt[0];
y = pt[1];
@ -745,15 +746,15 @@ static void S_StartSound(fixed_t* pt, fixed_t x, fixed_t y, int channel,
void S_SoundID(int channel, int sound_id, float volume, int attenuation)
{
S_StartSound((fixed_t *)NULL, 0, 0, channel, sound_id, volume, attenuation, false);
S_StartSound(nullptr, 0, 0, channel, sound_id, volume, attenuation, false);
}
void S_SoundID(fixed_t x, fixed_t y, int channel, int sound_id, float volume, int attenuation)
{
S_StartSound((fixed_t *)NULL, x, y, channel, sound_id, volume, attenuation, false);
S_StartSound(nullptr, x, y, channel, sound_id, volume, attenuation, false);
}
void S_SoundID(AActor *ent, int channel, int sound_id, float volume, int attenuation)
void S_SoundID(const AActor *ent, int channel, int sound_id, float volume, int attenuation)
{
if (!ent)
return;
@ -764,12 +765,12 @@ void S_SoundID(AActor *ent, int channel, int sound_id, float volume, int attenua
S_StartSound (&ent->x, 0, 0, channel, sound_id, volume, attenuation, false);
}
void S_SoundID(fixed_t *pt, int channel, int sound_id, float volume, int attenuation)
void S_SoundID(const fixed_t *pt, int channel, int sound_id, float volume, int attenuation)
{
S_StartSound(pt, 0, 0, channel, sound_id, volume, attenuation, false);
}
void S_LoopedSoundID(AActor *ent, int channel, int sound_id, float volume, int attenuation)
void S_LoopedSoundID(const AActor *ent, int channel, int sound_id, float volume, int attenuation)
{
if (!ent)
return;
@ -780,12 +781,35 @@ void S_LoopedSoundID(AActor *ent, int channel, int sound_id, float volume, int a
S_StartSound(&ent->x, 0, 0, channel, sound_id, volume, attenuation, true);
}
void S_LoopedSoundID(fixed_t *pt, int channel, int sound_id, float volume, int attenuation)
void S_LoopedSoundID(const fixed_t *pt, int channel, int sound_id, float volume, int attenuation)
{
S_StartSound(pt, 0, 0, channel, sound_id, volume, attenuation, true);
}
static void S_StartNamedSound(AActor *ent, fixed_t *pt, fixed_t x, fixed_t y, int channel,
int S_FindGenderedSound(std::string_view name, const AActor* ent)
{
static constexpr std::string_view templat = "player/{}/{}";
// static constexpr std::string_view genders[] = { "male", "female", "cyborg", "other" };
static constexpr std::string_view genders[] = { "male", "male", "male", "male" };
player_t *player;
int sfx_id = -1;
if (ent && ent != (AActor *)(~0) && (player = ent->player))
{
sfx_id = S_FindSound(fmt::format(templat, "base", name).c_str());
if (sfx_id == -1)
{
sfx_id = S_FindSound(fmt::format(templat, genders[player->userinfo.gender], name).c_str());
}
}
if (sfx_id == -1)
{
sfx_id = S_FindSound(fmt::format(templat, "male", name).c_str());
}
return sfx_id;
}
static void S_StartNamedSound(const AActor *ent, const fixed_t *pt, fixed_t x, fixed_t y, int channel,
const char *name, float volume, int attenuation, bool looping,
float dist_scale = 0.0f)
{
@ -805,30 +829,7 @@ static void S_StartNamedSound(AActor *ent, fixed_t *pt, fixed_t x, fixed_t y, in
if (soundname[0] == '*')
{
// Sexed sound
char nametemp[128];
const char templat[] = "player/%s/%s";
// Hacks away! -joek
//const char *genders[] = { "male", "female", "cyborg" };
const char *genders[] = { "male", "male", "male" };
player_t *player;
sfx_id = -1;
if (ent && ent != (AActor *)(~0) && (player = ent->player))
{
snprintf(nametemp, 128, templat, "base", soundname.substr(1).c_str());
sfx_id = S_FindSound(nametemp);
if (sfx_id == -1)
{
snprintf(nametemp, 128, templat, genders[player->userinfo.gender], soundname.substr(1).c_str());
sfx_id = S_FindSound(nametemp);
}
}
if (sfx_id == -1)
{
snprintf(nametemp, 128, templat, "male", soundname.substr(1).c_str());
sfx_id = S_FindSound(nametemp);
}
sfx_id = S_FindGenderedSound(soundname.substr(1), ent);
}
else
sfx_id = S_FindSound(soundname.c_str());
@ -851,7 +852,7 @@ static void S_StartNamedSound(AActor *ent, fixed_t *pt, fixed_t x, fixed_t y, in
void S_PlatSound(fixed_t *pt, int channel, const char *name, float volume, int attenuation)
{
if (!predicting)
S_StartNamedSound(NULL, pt, 0, 0, channel, name, volume, attenuation, false);
S_StartNamedSound(nullptr, pt, 0, 0, channel, name, volume, attenuation, false);
}
void S_Sound(int channel, const char *name, float volume, int attenuation)
@ -859,35 +860,35 @@ void S_Sound(int channel, const char *name, float volume, int attenuation)
// [SL] 2011-05-27 - This particular S_Sound() function is only used for sounds
// that should be full volume regardless of location. Ignore the specified
// attenuation and use ATTN_NONE instead.
S_StartNamedSound((AActor *)NULL, NULL, 0, 0, channel, name, volume, ATTN_NONE, false);
S_StartNamedSound(nullptr, nullptr, 0, 0, channel, name, volume, ATTN_NONE, false);
}
void S_Sound(AActor *ent, int channel, const char *name, float volume, int attenuation)
void S_Sound(const AActor *ent, int channel, const char *name, float volume, int attenuation)
{
if(!co_globalsound && channel == CHAN_ITEM && ent != listenplayer().camera)
return;
S_StartNamedSound(ent, NULL, 0, 0, channel, name, volume, attenuation, false);
S_StartNamedSound(ent, nullptr, 0, 0, channel, name, volume, attenuation, false);
}
void S_Sound(fixed_t *pt, int channel, const char *name, float volume, int attenuation)
void S_Sound(const fixed_t *pt, int channel, const char *name, float volume, int attenuation)
{
S_StartNamedSound(NULL, pt, 0, 0, channel, name, volume, attenuation, false);
S_StartNamedSound(nullptr, pt, 0, 0, channel, name, volume, attenuation, false);
}
void S_LoopedSound(AActor *ent, int channel, const char *name, float volume, int attenuation)
void S_LoopedSound(const AActor *ent, int channel, const char *name, float volume, int attenuation)
{
S_StartNamedSound(ent, NULL, 0, 0, channel, name, volume, attenuation, true);
S_StartNamedSound(ent, nullptr, 0, 0, channel, name, volume, attenuation, true);
}
void S_LoopedSound(fixed_t *pt, int channel, const char *name, float volume, int attenuation)
void S_LoopedSound(const fixed_t *pt, int channel, const char *name, float volume, int attenuation)
{
S_StartNamedSound(NULL, pt, 0, 0, channel, name, volume, attenuation, true);
S_StartNamedSound(nullptr, pt, 0, 0, channel, name, volume, attenuation, true);
}
void S_Sound(fixed_t x, fixed_t y, int channel, const char *name, float volume, int attenuation)
{
S_StartNamedSound((AActor *)(~0), NULL, x, y, channel, name, volume, attenuation, false);
S_StartNamedSound(nullptr, nullptr, x, y, channel, name, volume, attenuation, false);
}
@ -896,7 +897,7 @@ void S_Sound(fixed_t x, fixed_t y, int channel, const char *name, float volume,
//
static void S_StopChannel(unsigned int cnum)
{
if (::Channel == NULL)
if (::Channel == nullptr)
return;
if (cnum >= numChannels)
@ -914,7 +915,7 @@ static void S_StopChannel(unsigned int cnum)
}
void S_StopSound(fixed_t *pt)
void S_StopSound(const fixed_t *pt)
{
for (unsigned int i = 0; i < numChannels; i++)
if (Channel[i].sfxinfo && (Channel[i].pt == pt))
@ -923,9 +924,9 @@ void S_StopSound(fixed_t *pt)
}
}
void S_StopSound(fixed_t *pt, int channel)
void S_StopSound(const fixed_t *pt, int channel)
{
if (::Channel == NULL)
if (::Channel == nullptr)
return;
for (unsigned int i = 0; i < numChannels; i++)
@ -935,7 +936,7 @@ void S_StopSound(fixed_t *pt, int channel)
S_StopChannel(i);
}
void S_StopSound(AActor *ent, int channel)
void S_StopSound(const AActor *ent, int channel)
{
S_StopSound(&ent->x, channel);
}
@ -989,17 +990,17 @@ void S_ResumeSound()
// Moves all the sounds from one thing to another. If the destination is
// NULL, then the sound becomes a positioned sound.
void S_RelinkSound(AActor *from, AActor *to)
// nullptr, then the sound becomes a positioned sound.
void S_RelinkSound(const AActor *from, const AActor *to)
{
if (::Channel == NULL)
if (::Channel == nullptr)
return;
if (!from)
return;
const fixed_t *frompt = &from->x;
fixed_t *topt = to ? &to->x : NULL;
const fixed_t *topt = to ? &to->x : nullptr;
for (unsigned int i = 0; i < numChannels; i++)
{
@ -1012,7 +1013,7 @@ void S_RelinkSound(AActor *from, AActor *to)
}
}
bool S_GetSoundPlayingInfo(fixed_t *pt, int sound_id)
bool S_GetSoundPlayingInfo(const fixed_t *pt, int sound_id)
{
for (unsigned int i = 0; i < numChannels; i++)
{
@ -1022,9 +1023,9 @@ bool S_GetSoundPlayingInfo(fixed_t *pt, int sound_id)
return false;
}
bool S_GetSoundPlayingInfo(AActor *ent, int sound_id)
bool S_GetSoundPlayingInfo(const AActor *ent, int sound_id)
{
return S_GetSoundPlayingInfo (ent ? &ent->x : NULL, sound_id);
return S_GetSoundPlayingInfo (ent ? &ent->x : nullptr, sound_id);
}
//
@ -1052,12 +1053,11 @@ void S_ResumeMusic()
// Updates music & sounds
//
// joek - from choco again
void S_UpdateSounds(void* listener_p)
void S_UpdateSounds(const AActor* listener)
{
if (::Channel == NULL)
if (::Channel == nullptr)
return;
AActor* listener = (AActor*)listener_p;
for (int cnum = 0; cnum < (int)numChannels; cnum++)
{
channel_t* c = &Channel[cnum];
@ -1139,7 +1139,7 @@ void S_UpdateMusic()
void S_SetMusicVolume(float volume)
{
if (volume < 0.0 || volume > 1.0)
Printf (PRINT_HIGH, "Attempt to set music volume at %f\n", volume);
PrintFmt(PRINT_HIGH, "Attempt to set music volume at {}\n", volume);
else
I_SetMusicVolume (volume);
}
@ -1147,7 +1147,7 @@ void S_SetMusicVolume(float volume)
void S_SetSfxVolume(float volume)
{
if (volume < 0.0 || volume > 1.0)
Printf (PRINT_HIGH, "Attempt to set sfx volume at %f\n", volume);
PrintFmt(PRINT_HIGH, "Attempt to set sfx volume at {}\n", volume);
else
I_SetSfxVolume (volume);
}
@ -1162,7 +1162,7 @@ void S_StartMusic(const char *m_id)
// [RH] S_ChangeMusic() now accepts the name of the music lump.
// It's up to the caller to figure out what that name is.
void S_ChangeMusic(std::string musicname, bool looping)
void S_ChangeMusic(std::string musicname, bool looping, int order)
{
// [SL] Avoid caching music lumps if we're not playing music
if (snd_musicsystem == MS_NONE)
@ -1178,7 +1178,7 @@ void S_ChangeMusic(std::string musicname, bool looping)
return;
}
byte* data = NULL;
byte* data = nullptr;
size_t length = 0;
FILE *f;
@ -1187,13 +1187,13 @@ void S_ChangeMusic(std::string musicname, bool looping)
int lumpnum;
if ((lumpnum = W_CheckNumForName (musicname.c_str())) == -1)
{
Printf (PRINT_HIGH, "Music lump \"%s\" not found\n", musicname);
PrintFmt(PRINT_HIGH, "Music lump \"{}\" not found\n", musicname);
return;
}
data = static_cast<byte*>(W_CacheLumpNum(lumpnum, PU_CACHE));
length = W_LumpLength(lumpnum);
I_PlaySong({data, length}, looping);
I_PlaySong({data, length}, looping, order);
}
else
{
@ -1204,7 +1204,7 @@ void S_ChangeMusic(std::string musicname, bool looping)
if (result == 1)
{
I_PlaySong({data, length}, looping);
I_PlaySong({data, length}, looping, order);
}
M_Free(data);
}
@ -1216,7 +1216,7 @@ void S_StopMusic()
{
I_StopSong();
mus_playing.name = "";
mus_playing.name.clear();
}
@ -1227,355 +1227,13 @@ void S_StopMusic()
//
// =============================== [RH]
typedef enum
{
AMB_TYPE_NONE,
AMB_TYPE_POINT,
AMB_TYPE_WORLD,
} amb_type_t;
typedef enum
{
AMB_MODE_NONE,
AMB_MODE_CONTINUOUS,
AMB_MODE_RANDOM,
AMB_MODE_PERIODIC,
} amb_mode_t;
static struct AmbientSound {
amb_type_t type; // Ambient sound type
amb_mode_t mode; // Ambient sound mode
int periodmin; // # of tics between repeats
int periodmax; // max # of tics for random ambients
float volume; // relative volume of sound
float attenuation; // Used for distance scaling
char sound[MAX_SNDNAME+1]; // Logical name of sound to play
} Ambients[256];
void S_HashSounds()
{
// Mark all buckets as empty
for (auto& sfx : S_sfx)
sfx.index = ~0;
// Now set up the chains
for (unsigned i = 0; i < S_sfx.size(); i++)
{
const unsigned j = MakeKey(S_sfx[i].name) % static_cast<unsigned>(S_sfx.size() - 1);
S_sfx[i].next = S_sfx[j].index;
S_sfx[j].index = i;
}
}
int S_FindSound(const char *logicalname)
{
if (S_sfx.empty())
return -1;
int i = S_sfx[MakeKey(logicalname) % static_cast<unsigned>(S_sfx.size() - 1)].index;
while ((i != -1) && strnicmp(S_sfx[i].name, logicalname, MAX_SNDNAME))
i = S_sfx[i].next;
return i;
}
int S_FindSoundByLump(int lump)
{
if (lump != -1)
{
for (unsigned i = 0; i < S_sfx.size(); i++)
if (S_sfx[i].lumpnum == lump)
return i;
}
return -1;
}
size_t S_AddSoundLump(const char *logicalname, int lump)
{
sfxinfo_t& new_sfx = S_sfx.emplace_back();
// logicalname MUST be <= MAX_SNDNAME chars long
M_StringCopy(new_sfx.name, logicalname, MAX_SNDNAME + 1);
new_sfx.data = NULL;
new_sfx.link = sfxinfo_t::NO_LINK;
new_sfx.lumpnum = lump;
return S_sfx.size() - 1;
}
void S_ClearSoundLumps()
{
S_sfx.clear();
S_rnd.clear();
}
size_t FindSoundNoHash(const char* logicalname)
{
for (size_t i = 0; i < S_sfx.size(); i++)
if (iequals(logicalname, S_sfx[i].name))
return i;
return S_sfx.size();
}
size_t FindSoundTentative(const char* name)
{
size_t id = FindSoundNoHash(name);
if (id == S_sfx.size())
{
id = S_AddSoundLump(name, -1);
}
return id;
}
size_t S_AddSound(const char *logicalname, const char *lumpname)
{
size_t sfxid = FindSoundNoHash(logicalname);
const int lump = lumpname ? W_CheckNumForName(lumpname) : -1;
// Otherwise, prepare a new one.
if (sfxid != S_sfx.size())
{
sfxinfo_t& sfx = S_sfx[sfxid];
sfx.lumpnum = lump;
sfx.link = sfxinfo_t::NO_LINK;
if (sfx.israndom)
{
S_rnd.erase(sfxid);
sfx.israndom = false;
}
}
else
sfxid = S_AddSoundLump(logicalname, lump);
return sfxid;
}
void S_AddRandomSound(size_t owner, std::vector<size_t>& list)
{
S_rnd[owner] = list;
S_sfx[owner].link = owner;
S_sfx[owner].israndom = true;
}
// S_ParseSndInfo
// Parses all loaded SNDINFO lumps.
void S_ParseSndInfo()
{
S_ClearSoundLumps();
int lump = -1;
while ((lump = W_FindLump("SNDINFO", lump)) != -1)
{
char* buffer = static_cast<char*>(W_CacheLumpNum(lump, PU_CACHE));
const OScannerConfig config = {
"SNDINFO", // lumpName
true, // semiComments
true, // cComments
};
OScanner os = OScanner::openBuffer(config, buffer, buffer + W_LumpLength(lump));
while (os.scan())
{
std::string tok = os.getToken();
// check if token is a command
if (tok[0] == '$')
{
os.mustScan();
if (os.compareTokenNoCase("ambient"))
{
// $ambient <num> <logical name> [point [atten]|surround] <type>
// [secs] <relative volume>
AmbientSound *ambient, dummy;
os.mustScanInt();
const int index = os.getTokenInt();
if (index < 0 || index > 255)
{
os.warning("Bad ambient index ({})\n", index);
ambient = &dummy;
}
else
{
ambient = Ambients + index;
}
ambient->type = AMB_TYPE_NONE;
ambient->mode = AMB_MODE_NONE;
ambient->periodmin = 0;
ambient->periodmax = 0;
ambient->volume = 0.0f;
os.mustScan();
strncpy(ambient->sound, os.getToken().c_str(), MAX_SNDNAME);
ambient->sound[MAX_SNDNAME] = 0;
ambient->attenuation = 0.0f; // No change by default
os.mustScan();
if (os.compareTokenNoCase("point"))
{
ambient->type = AMB_TYPE_POINT;
os.mustScan();
if (IsRealNum(os.getToken().c_str()))
{
if (os.getTokenFloat() > 0.0f)
{
ambient->attenuation = os.getTokenFloat();
}
os.mustScan();
}
}
else
{
ambient->type = AMB_TYPE_WORLD;
if (os.compareTokenNoCase("surround") ||
os.compareTokenNoCase("world"))
{
os.mustScan();
}
}
if (os.compareTokenNoCase("continuous"))
{
ambient->mode = AMB_MODE_CONTINUOUS;
}
else if (os.compareTokenNoCase("random"))
{
ambient->mode = AMB_MODE_RANDOM;
os.mustScanFloat();
ambient->periodmin = static_cast<int>(os.getTokenFloat() * TICRATE);
os.mustScanFloat();
ambient->periodmax = static_cast<int>(os.getTokenFloat() * TICRATE);
}
else if (os.compareTokenNoCase("periodic"))
{
ambient->mode = AMB_MODE_PERIODIC;
os.mustScanFloat();
ambient->periodmin = static_cast<int>(os.getTokenFloat() * TICRATE);
}
else
{
os.warning("Unknown ambient type ({})\n", os.getToken());
}
ambient->periodmin = MAX(0, ambient->periodmin);
ambient->periodmax = MAX(ambient->periodmin, ambient->periodmax);
os.mustScanFloat();
ambient->volume = clamp(os.getTokenFloat(), 0.0f, 1.0f);
if (ambient->mode == AMB_MODE_NONE || ambient->volume == 0.0f ||
(ambient->mode != AMB_MODE_CONTINUOUS &&
ambient->periodmin == 0 && ambient->periodmax == 0))
{
// Ignore bad ambient sounds
ambient->type = AMB_TYPE_NONE;
}
}
else if (os.compareTokenNoCase("map"))
{
// Hexen-style $MAP command
char mapname[8];
os.mustScanInt();
snprintf(mapname, 8, "MAP%02d", os.getTokenInt());
level_pwad_info_t& info = getLevelInfos().findByName(mapname);
os.mustScan();
if (info.mapname[0])
{
info.music = os.getToken();
}
}
else if (os.compareTokenNoCase("alias"))
{
os.mustScan();
const size_t sfxfrom = S_AddSound(os.getToken().c_str(), NULL);
os.mustScan();
S_sfx[sfxfrom].link = FindSoundTentative(os.getToken().c_str());
}
else if (os.compareTokenNoCase("random"))
{
std::vector<size_t> list;
os.mustScan();
const size_t owner = S_AddSound(os.getToken().c_str(), NULL);
os.mustScan();
os.assertTokenIs("{");
while (os.scan() && !os.compareToken("}"))
{
const size_t sfxto = FindSoundTentative(os.getToken().c_str());
if (owner == sfxto)
{
os.warning("Definition of random sound '{}' refers to itself "
"recursively.\n", os.getToken());
continue;
}
list.push_back(sfxto);
}
if (list.size() == 1)
{
// only one sound; treat as alias
S_sfx[owner].link = list[0];
}
else if (list.size() > 1)
{
S_AddRandomSound(owner, list);
}
}
else
{
os.warning("Unknown SNDINFO command {}\n", os.getToken());
while (os.scan())
if (os.crossed())
{
os.unScan();
break;
}
}
}
else
{
// token is a logical sound mapping
char name[MAX_SNDNAME + 1];
strncpy(name, tok.c_str(), MAX_SNDNAME);
name[MAX_SNDNAME] = 0;
os.mustScan();
if (os.compareToken("="))
{
os.mustScan();
}
S_AddSound(name, os.getToken().c_str());
}
}
}
S_HashSounds();
sfx_empty = W_CheckNumForName("dsempty");
sfx_noway = S_FindSoundByLump(W_CheckNumForName("dsnoway"));
sfx_oof = S_FindSoundByLump(W_CheckNumForName("dsoof"));
}
static void SetTicker(int *tics, AmbientSound *ambient)
{
if (ambient->mode == AMB_MODE_CONTINUOUS)
if (ambient->mode == amb_mode_t::CONTINUOUS)
{
*tics = 1;
}
else if (ambient->mode == AMB_MODE_RANDOM)
else if (ambient->mode == amb_mode_t::RANDOM)
{
*tics = (int)(((float)rand() / (float)RAND_MAX) *
(float)(ambient->periodmax - ambient->periodmin)) +
@ -1599,7 +1257,7 @@ void A_Ambient(AActor *actor)
AmbientSound *ambient = &Ambients[actor->args[0]];
if (ambient->mode == AMB_MODE_CONTINUOUS)
if (ambient->mode == amb_mode_t::CONTINUOUS)
{
if (S_GetSoundPlayingInfo (actor, S_FindSound (ambient->sound)))
return;
@ -1607,8 +1265,8 @@ void A_Ambient(AActor *actor)
if (ambient->sound[0])
{
const int attn_type =
(ambient->type == AMB_TYPE_POINT ? ATTN_IDLE : ATTN_NONE);
S_StartNamedSound(actor, NULL, 0, 0, CHAN_AMBIENT, ambient->sound,
(ambient->type == amb_type_t::POINT ? ATTN_IDLE : ATTN_NONE);
S_StartNamedSound(actor, nullptr, 0, 0, CHAN_AMBIENT, ambient->sound,
ambient->volume, attn_type, true, ambient->attenuation);
SetTicker (&actor->tics, ambient);
@ -1623,8 +1281,8 @@ void A_Ambient(AActor *actor)
if (ambient->sound[0])
{
const int attn_type =
(ambient->type == AMB_TYPE_POINT ? ATTN_IDLE : ATTN_NONE);
S_StartNamedSound(actor, NULL, 0, 0, CHAN_AMBIENT, ambient->sound,
(ambient->type == amb_type_t::POINT ? ATTN_IDLE : ATTN_NONE);
S_StartNamedSound(actor, nullptr, 0, 0, CHAN_AMBIENT, ambient->sound,
ambient->volume, attn_type, false, ambient->attenuation);
SetTicker (&actor->tics, ambient);
@ -1643,12 +1301,12 @@ void S_ActivateAmbient(AActor *origin, int ambient)
AmbientSound *amb = &Ambients[ambient];
if (amb->type == AMB_TYPE_NONE)
if (amb->type == amb_type_t::NONE)
{
return;
}
if (amb->mode != AMB_MODE_CONTINUOUS && amb->periodmin == 0)
if (amb->mode != amb_mode_t::CONTINUOUS && amb->periodmin == 0)
{
const int sndnum = S_FindSound(amb->sound);
if (sndnum == 0 || sndnum == -1)
@ -1671,11 +1329,11 @@ BEGIN_COMMAND (snd_soundlist)
if (S_sfx[i].lumpnum != -1)
{
const OLumpName lumpname = lumpinfo[S_sfx[i].lumpnum].name;
Printf(PRINT_HIGH, "%3d. %s (%s)\n", i+1, S_sfx[i].name, lumpname.c_str());
PrintFmt(PRINT_HIGH, "{:>3d}. {} ({})\n", i+1, S_sfx[i].name, lumpname);
}
// todo: check if sounds are multiple lumps rather than just one (i.e. random sounds)
else
Printf (PRINT_HIGH, "%3d. %s **not present**\n", i+1, S_sfx[i].name);
PrintFmt(PRINT_HIGH, "{:>3d}. {} **not present**\n", i+1, S_sfx[i].name);
}
END_COMMAND (snd_soundlist)
@ -1683,7 +1341,7 @@ BEGIN_COMMAND (snd_soundlinks)
{
for (const auto& sfx : S_sfx)
if (sfx.link != static_cast<int>(sfxinfo_t::NO_LINK))
Printf(PRINT_HIGH, "%s -> %s\n", sfx.name, S_sfx[sfx.link].name);
PrintFmt(PRINT_HIGH, "{} -> {}\n", sfx.name, S_sfx[sfx.link].name);
}
END_COMMAND (snd_soundlinks)
@ -1698,11 +1356,11 @@ BEGIN_COMMAND (changemus)
{
if (argc == 1)
{
Printf(PRINT_HIGH, "Usage: changemus lumpname [loop]");
Printf(PRINT_HIGH, "\n");
Printf(PRINT_HIGH, "Plays music from an internal lump, loop\n");
Printf(PRINT_HIGH, "parameter determines if the music should play\n");
Printf(PRINT_HIGH, "continuously or not, (1 or 0, default: 1)\n");
PrintFmt(PRINT_HIGH, "Usage: changemus lumpname [loop]");
PrintFmt(PRINT_HIGH, "\n");
PrintFmt(PRINT_HIGH, "Plays music from an internal lump, loop\n");
PrintFmt(PRINT_HIGH, "parameter determines if the music should play\n");
PrintFmt(PRINT_HIGH, "continuously or not, (1 or 0, default: 1)\n");
return;
}
@ -1725,7 +1383,7 @@ END_COMMAND (changemus)
// UV_SoundAvoidCl
// Sends a sound to clients, but doesn't send it to client 'player'.
//
void UV_SoundAvoidPlayer(AActor *mo, byte channel, const char *name, byte attenuation)
void UV_SoundAvoidPlayer(const AActor *mo, byte channel, const char *name, byte attenuation)
{
S_Sound(mo, channel, name, 1, attenuation);
}

View file

@ -438,6 +438,33 @@ void ST_voteDraw (int y) {
true, false, true);
ST_DrawBar(CR_GREEN, vote_state.yes, vote_state.yes_needed,
(I_GetSurfaceWidth() >> 1), y, xscale * 40, false, true);
// [RV] Show bound keys for YES/NO while vote is undecided
if (vote_state.result == VOTE_UNDEC)
{
// Use the same binding helper as the warmup code
const std::string yesKey = ::Bindings.GetKeynameFromCommand("vote_yes");
const std::string noKey = ::Bindings.GetKeynameFromCommand("vote_no");
// Fallbacks if nothing bound
const char* yesStr = yesKey.empty() ? "Y" : yesKey.c_str();
const char* noStr = noKey.empty() ? "N" : noKey.c_str();
// Match the warmup style (fmt::sprintf + TEXTCOLOR_* tags)
const std::string hint = fmt::sprintf(
"Press %s%s%s for %sYES%s, %s%s%s for %sNO%s", TEXTCOLOR_GOLD, yesStr,
TEXTCOLOR_NORMAL, TEXTCOLOR_GREEN, TEXTCOLOR_NORMAL, TEXTCOLOR_GOLD, noStr,
TEXTCOLOR_NORMAL, TEXTCOLOR_RED, TEXTCOLOR_NORMAL);
int hint_w = V_StringWidth(hint.c_str()) * xscale;
int hx = (I_GetSurfaceWidth() - hint_w) >> 1;
y += yscale * 8; // place one line below the votestring lines
if (hud_scale)
screen->DrawTextClean(CR_GRAY, hx, y, hint.c_str());
else
screen->DrawText(CR_GRAY, hx, y, hint.c_str());
}
}
namespace hud {

View file

@ -645,7 +645,7 @@ BEGIN_COMMAND (idmus)
map = CalcMapName(0, l);
else
{
Printf(PRINT_HIGH, "%s\n", GStrings(STSTR_NOMUS));
PrintFmt(PRINT_HIGH, "{}\n", GStrings(STSTR_NOMUS));
return;
}
}
@ -660,12 +660,12 @@ BEGIN_COMMAND (idmus)
if (info.music[0])
{
S_ChangeMusic(std::string(info.music.c_str(), 8), 1);
Printf(PRINT_HIGH, "%s\n", GStrings(STSTR_MUS));
PrintFmt(PRINT_HIGH, "{}\n", GStrings(STSTR_MUS));
}
}
else
{
Printf(PRINT_HIGH, "%s\n", GStrings(STSTR_NOMUS));
PrintFmt(PRINT_HIGH, "{}\n", GStrings(STSTR_NOMUS));
}
}
}
@ -694,7 +694,7 @@ BEGIN_COMMAND (fov)
return;
if (argc != 2)
Printf(PRINT_HIGH, "FOV is %g\n", m_Instigator->player->fov);
PrintFmt(PRINT_HIGH, "FOV is {:g}\n", m_Instigator->player->fov);
else
{
m_Instigator->player->fov = clamp((float)atof(argv[1]), 45.0f, 135.0f);

Some files were not shown because too many files have changed in this diff Show more