├── .coderabbit.yaml ├── .editorconfig ├── .gitattributes ├── .github ├── DISCUSSION_TEMPLATE │ └── ideas-and-feedback.yml ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── config.yml │ ├── phobos_bug_report.yml │ └── vanilla_bugfix_request.yml ├── actions │ └── build-phobos │ │ └── action.yml ├── dependabot.yml ├── labeler.yml ├── pull_request_template.md └── workflows │ ├── labeler-action.yml │ ├── nightly.yml │ ├── pr-doc-checker.yml │ ├── pr-nightly-comment.yml │ └── pr-nightly.yml ├── .gitignore ├── .gitmodules ├── .readthedocs.yaml ├── .vscode ├── c_cpp_properties.example.json ├── extensions.json ├── launch.json ├── settings.example.json └── tasks.json ├── .vsconfig ├── CREDITS.md ├── LICENSE.md ├── Phobos.sln ├── Phobos.vcxproj ├── README.md ├── docs ├── AI-Scripting-and-Mapping.md ├── CREDITS.md ├── Contributing.md ├── Fixed-or-Improved-Logics.md ├── General-Info.md ├── License.md ├── Makefile ├── Miscellanous.md ├── New-or-Enhanced-Logics.md ├── User-Interface.md ├── Whats-New.md ├── _static │ ├── css │ │ ├── dark.css │ │ └── index.css │ ├── icons │ │ ├── auto.svg │ │ ├── dark.svg │ │ ├── light.svg │ │ └── status.svg │ ├── images │ │ ├── VoxelLightSourceComparison.png │ │ ├── animToUnit.gif │ │ ├── buildingQueue.png │ │ ├── cust-Chrono.gif │ │ ├── digital_display_shapes.png │ │ ├── disklaser-radius-values-01.gif │ │ ├── ebolt.gif │ │ ├── feedbackweapon.gif │ │ ├── forceweapon_emp.gif │ │ ├── grinding.gif │ │ ├── hackerfinallyworks-01.gif │ │ ├── harvestercounter-01.gif │ │ ├── healthbar.hide-01.png │ │ ├── initialstrength.cloning-01.png │ │ ├── issinglecolor.gif │ │ ├── jumpjet-tilt.gif │ │ ├── jumpjet-turning.gif │ │ ├── lasertrails.gif │ │ ├── lowpriority-01.gif │ │ ├── mindcontrol-max-range-01.gif │ │ ├── mindcontrol-multiple-01.gif │ │ ├── objectinfo-01.png │ │ ├── ore-01.png │ │ ├── oregath.gif │ │ ├── placepreview.png │ │ ├── powerdelta-01.gif │ │ ├── powersup.owner-01.png │ │ ├── preserve-ic.gif │ │ ├── producing-progress-01.gif │ │ ├── projectile-interception-01.gif │ │ ├── promotedspawns-01.gif │ │ ├── radtype-01.png │ │ ├── remember-target-after-deploying-01.gif │ │ ├── remove-mc.gif │ │ ├── shrapnel.gif │ │ ├── spawnrange-01.gif │ │ ├── splashlist-01.gif │ │ ├── strafing-01.gif │ │ ├── straight.gif │ │ ├── sw_sidebar.png │ │ ├── swnext.gif │ │ ├── technoshield-01.gif │ │ ├── tooltips-01.png │ │ ├── translucency-fix.png │ │ ├── tree-shake.gif │ │ ├── turretoffset-01.png │ │ ├── underwater-new-attack-tag.gif │ │ └── weaponfilter.gif │ └── js │ │ ├── ini-block-maker.js │ │ └── scheme-switcher.js ├── _templates │ └── layout.html ├── conf.py ├── index.md ├── locale │ └── zh_CN │ │ └── LC_MESSAGES │ │ ├── AI-Scripting-and-Mapping.po │ │ ├── CREDITS.po │ │ ├── Contributing.po │ │ ├── Fixed-or-Improved-Logics.po │ │ ├── General-Info.po │ │ ├── License.po │ │ ├── Miscellanous.po │ │ ├── New-or-Enhanced-Logics.po │ │ ├── User-Interface.po │ │ ├── Whats-New.po │ │ └── index.po ├── make.bat └── requirements.txt ├── images └── ChrisLv-relicense.png ├── lib ├── .editorconfig └── nameof │ └── nameof.h ├── logo-mono.png ├── logo.png ├── scripts ├── build_debug.bat ├── build_devbuild.bat ├── build_docs.bat ├── build_docs_locale.bat ├── build_release.bat ├── clean.bat ├── configure_vscode_cpp.bat ├── run_msbuild.bat ├── run_vsdevcmd.bat └── vswhere.exe └── src ├── Blowfish ├── Hooks.Blowfish.cpp ├── blowfish.cpp └── blowfish.h ├── Commands ├── Commands.cpp ├── Commands.h ├── DamageDisplay.cpp ├── DamageDisplay.h ├── Dummy.cpp ├── Dummy.h ├── FireTacticalSW.h ├── FrameByFrame.cpp ├── FrameByFrame.h ├── FrameStep.cpp ├── FrameStep.h ├── NextIdleHarvester.cpp ├── NextIdleHarvester.h ├── ObjectInfo.cpp ├── ObjectInfo.h ├── QuickSave.cpp ├── QuickSave.h ├── SaveVariablesToFile.cpp ├── SaveVariablesToFile.h ├── ToggleDesignatorRange.cpp ├── ToggleDesignatorRange.h ├── ToggleDigitalDisplay.cpp ├── ToggleDigitalDisplay.h ├── ToggleSWSidebar.cpp └── ToggleSWSidebar.h ├── Ext ├── Aircraft │ ├── Body.cpp │ ├── Body.h │ └── Hooks.cpp ├── Anim │ ├── Body.cpp │ ├── Body.h │ ├── Hooks.AnimCreateUnit.cpp │ └── Hooks.cpp ├── AnimType │ ├── Body.cpp │ └── Body.h ├── Building │ ├── Body.cpp │ ├── Body.h │ ├── Hooks.Grinding.cpp │ ├── Hooks.Production.cpp │ ├── Hooks.Refinery.cpp │ ├── Hooks.Selling.cpp │ └── Hooks.cpp ├── BuildingType │ ├── Body.cpp │ ├── Body.h │ ├── Hooks.Upgrade.cpp │ └── Hooks.cpp ├── Bullet │ ├── Body.cpp │ ├── Body.h │ ├── Hooks.DetonateLogics.cpp │ ├── Hooks.Obstacles.cpp │ ├── Hooks.cpp │ └── Trajectories │ │ ├── BombardTrajectory.cpp │ │ ├── BombardTrajectory.h │ │ ├── ParabolaTrajectory.cpp │ │ ├── ParabolaTrajectory.h │ │ ├── PhobosTrajectory.cpp │ │ ├── PhobosTrajectory.h │ │ ├── SampleTrajectory.cpp │ │ ├── SampleTrajectory.h │ │ ├── StraightTrajectory.cpp │ │ └── StraightTrajectory.h ├── BulletType │ ├── Body.cpp │ └── Body.h ├── CaptureManager │ ├── Body.cpp │ ├── Body.h │ └── Hooks.cpp ├── Cell │ ├── Body.cpp │ └── Body.h ├── Event │ ├── Body.cpp │ └── Body.h ├── House │ ├── Body.cpp │ ├── Body.h │ ├── Hooks.AINavalProduction.cpp │ ├── Hooks.ForceEnemy.cpp │ ├── Hooks.UnitFromFactory.cpp │ └── Hooks.cpp ├── OverlayType │ ├── Body.cpp │ ├── Body.h │ └── Hooks.cpp ├── ParticleSystemType │ ├── Body.cpp │ └── Body.h ├── ParticleType │ ├── Body.cpp │ ├── Body.h │ └── Hooks.cpp ├── RadSite │ ├── Body.cpp │ ├── Body.h │ └── Hooks.cpp ├── Rules │ ├── Body.cpp │ ├── Body.h │ └── Hooks.Image.cpp ├── SWType │ ├── Body.cpp │ ├── Body.h │ ├── FireSuperWeapon.cpp │ ├── Hooks.cpp │ ├── NewSWType │ │ ├── NewSWType.cpp │ │ └── NewSWType.h │ └── SWHelpers.cpp ├── Scenario │ ├── Body.cpp │ ├── Body.h │ ├── Hooks.Variables.cpp │ ├── Hooks.Waypoints.cpp │ └── Hooks.cpp ├── Script │ ├── Body.cpp │ ├── Body.h │ ├── Hooks.cpp │ ├── Mission.Attack.cpp │ └── Mission.Move.cpp ├── Side │ ├── Body.cpp │ ├── Body.h │ ├── Hooks.SidebarGDIPositions.cpp │ └── Hooks.cpp ├── Sidebar │ ├── Body.cpp │ ├── Body.h │ ├── Hooks.cpp │ └── SWSidebar │ │ ├── SWButtonClass.cpp │ │ ├── SWButtonClass.h │ │ ├── SWColumnClass.cpp │ │ ├── SWColumnClass.h │ │ ├── SWSidebarClass.cpp │ │ ├── SWSidebarClass.h │ │ ├── ToggleSWButtonClass.cpp │ │ └── ToggleSWButtonClass.h ├── Surface │ ├── Body.cpp │ └── Body.h ├── TAction │ ├── Body.cpp │ ├── Body.h │ └── Hooks.cpp ├── TEvent │ ├── Body.cpp │ ├── Body.h │ └── Hooks.cpp ├── Team │ ├── Body.cpp │ ├── Body.h │ └── Hooks.cpp ├── Techno │ ├── Body.Internal.cpp │ ├── Body.Update.cpp │ ├── Body.Visuals.cpp │ ├── Body.cpp │ ├── Body.h │ ├── Hooks.Airstrike.cpp │ ├── Hooks.Cloak.cpp │ ├── Hooks.Firing.cpp │ ├── Hooks.Misc.cpp │ ├── Hooks.Pips.cpp │ ├── Hooks.ReceiveDamage.cpp │ ├── Hooks.TargetEvaluation.cpp │ ├── Hooks.Tint.cpp │ ├── Hooks.Transport.cpp │ ├── Hooks.WeaponEffects.cpp │ ├── Hooks.WeaponRange.cpp │ ├── Hooks.cpp │ └── WeaponHelpers.cpp ├── TechnoType │ ├── Body.cpp │ ├── Body.h │ ├── Hooks.MatrixOp.cpp │ ├── Hooks.Teleport.cpp │ └── Hooks.cpp ├── TerrainType │ ├── Body.cpp │ ├── Body.h │ ├── Hooks.Passable.cpp │ └── Hooks.cpp ├── Tiberium │ ├── Body.cpp │ ├── Body.h │ └── Hooks.cpp ├── Trigger │ └── Hooks.cpp ├── Unit │ ├── Hooks.Crushing.cpp │ ├── Hooks.DeployFire.cpp │ ├── Hooks.DeploysInto.cpp │ ├── Hooks.DisallowMoving.cpp │ ├── Hooks.Harvester.cpp │ ├── Hooks.Jumpjet.cpp │ ├── Hooks.Sinking.cpp │ └── Hooks.Unload.cpp ├── VoxelAnim │ ├── Body.cpp │ ├── Body.h │ └── Hooks.cpp ├── VoxelAnimType │ ├── Body.cpp │ └── Body.h ├── WarheadType │ ├── Body.cpp │ ├── Body.h │ ├── Detonate.cpp │ └── Hooks.cpp └── WeaponType │ ├── Body.cpp │ ├── Body.h │ ├── Hook.EBolt.cpp │ ├── Hooks.DiskLaserRadius.cpp │ └── Hooks.cpp ├── Locomotion ├── TestLocomotionClass.cpp └── TestLocomotionClass.h ├── Misc ├── BlittersFix.cpp ├── BlittersFix.h ├── FlyingStrings.cpp ├── FlyingStrings.h ├── Hooks.AlphaImage.cpp ├── Hooks.Ares.cpp ├── Hooks.BugFixes.cpp ├── Hooks.Crates.cpp ├── Hooks.Gamespeed.cpp ├── Hooks.INIInheritance.cpp ├── Hooks.LaserDraw.cpp ├── Hooks.LightEffects.cpp ├── Hooks.Overlay.cpp ├── Hooks.PCX.cpp ├── Hooks.SkirmishColors.cpp ├── Hooks.Timers.cpp ├── Hooks.UI.cpp ├── Hooks.VeinholeMonster.cpp ├── PhobosToolTip.cpp ├── PhobosToolTip.h ├── RetryDialog.cpp ├── Selection.cpp ├── SyncLogging.cpp ├── SyncLogging.h └── TextInput.cpp ├── New ├── Entity │ ├── AttachEffectClass.cpp │ ├── AttachEffectClass.h │ ├── LaserTrailClass.cpp │ ├── LaserTrailClass.h │ ├── ShieldClass.cpp │ └── ShieldClass.h └── Type │ ├── Affiliated │ ├── CreateUnitTypeClass.cpp │ ├── CreateUnitTypeClass.h │ ├── DroppodTypeClass.cpp │ ├── DroppodTypeClass.h │ ├── InterceptorTypeClass.cpp │ ├── InterceptorTypeClass.h │ ├── PassengerDeletionTypeClass.cpp │ ├── PassengerDeletionTypeClass.h │ ├── TiberiumEaterTypeClass.cpp │ ├── TiberiumEaterTypeClass.h │ ├── TypeConvertGroup.cpp │ └── TypeConvertGroup.h │ ├── AttachEffectTypeClass.cpp │ ├── AttachEffectTypeClass.h │ ├── DigitalDisplayTypeClass.cpp │ ├── DigitalDisplayTypeClass.h │ ├── InsigniaTypeClass.cpp │ ├── InsigniaTypeClass.h │ ├── LaserTrailTypeClass.cpp │ ├── LaserTrailTypeClass.h │ ├── RadTypeClass.cpp │ ├── RadTypeClass.h │ ├── SelectBoxTypeClass.cpp │ ├── SelectBoxTypeClass.h │ ├── ShieldTypeClass.cpp │ └── ShieldTypeClass.h ├── Phobos.COM.cpp ├── Phobos.COM.h ├── Phobos.CRT.cpp ├── Phobos.CRT.h ├── Phobos.Ext.cpp ├── Phobos.INI.cpp ├── Phobos.cpp ├── Phobos.h ├── Phobos.version.h ├── Utilities ├── Anchor.cpp ├── Anchor.h ├── AresAddressInit.cpp ├── AresFunctions.h ├── AresHelper.cpp ├── AresHelper.h ├── Constructs.cpp ├── Constructs.h ├── Container.h ├── Coroutine.h ├── Debug.cpp ├── Debug.h ├── Enum.h ├── EnumFunctions.cpp ├── EnumFunctions.h ├── Enumerable.h ├── GeneralUtils.cpp ├── GeneralUtils.h ├── Helpers.Alex.h ├── INIParser.h ├── Iterator.h ├── Macro.h ├── Parser.h ├── Patch.cpp ├── Patch.h ├── Savegame.h ├── SavegameDef.h ├── ShapeTextPrinter.cpp ├── ShapeTextPrinter.h ├── Stream.cpp ├── Stream.h ├── Swizzle.h ├── Template.h └── TemplateDef.h └── version.rc /.coderabbit.yaml: -------------------------------------------------------------------------------- 1 | reviews: 2 | request_changes_workflow: false 3 | high_level_summary: true 4 | poem: false 5 | review_status: false 6 | collapse_walkthrough: false 7 | auto_review: 8 | enabled: false 9 | chat: 10 | auto_reply: false 11 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text eol=crlf 2 | 3 | *.vcproj text eol=crlf 4 | *.c++ text eol=crlf 5 | *.cc text eol=crlf 6 | *.cpp text eol=crlf 7 | *.cppm text eol=crlf 8 | *.cxx text eol=crlf 9 | *.h text eol=crlf 10 | *.h++ text eol=crlf 11 | *.hh text eol=crlf 12 | *.hpp text eol=crlf 13 | *.hxx text eol=crlf 14 | *.inl text eol=crlf 15 | *.ipp text eol=crlf 16 | *.ixx text eol=crlf 17 | *.tlh text eol=crlf 18 | *.tli text eol=crlf 19 | 20 | *.sh text eol=lf 21 | 22 | *.gif -text 23 | *.jpg -text 24 | *.png -text 25 | *.exe -text 26 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: [github.com/Phobos-developers/Phobos#developers] 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Suggest a feature or enhancement 4 | url: https://github.com/Phobos-developers/Phobos/discussions/new?category=ideas-and-feedback 5 | about: If you want to suggest your idea to the project and/or upvote some idea. 6 | - name: Official channels on C&C Mod Haven 7 | url: https://discord.gg/an3bDxtksM 8 | about: If you want to discuss something with us without filing an issue. 9 | -------------------------------------------------------------------------------- /.github/actions/build-phobos/action.yml: -------------------------------------------------------------------------------- 1 | name: 'Build Phobos' 2 | inputs: 3 | sln-path: 4 | description: 'Path to the solution file relative to the root of the project' 5 | required: false 6 | default: '.' 7 | build-config: 8 | description: 'Configuration to build' 9 | required: true 10 | runs: 11 | using: "composite" 12 | steps: 13 | - name: Add MSBuild to PATH 14 | uses: microsoft/setup-msbuild@v1.1 15 | with: 16 | vs-version: '[16.0, )' 17 | 18 | - uses: ammaraskar/msvc-problem-matcher@master 19 | 20 | - name: Build 21 | working-directory: ${{env.GITHUB_WORKSPACE}} 22 | # Add additional options to the MSBuild command line here (like platform or verbosity level). 23 | # See https://docs.microsoft.com/visualstudio/msbuild/msbuild-command-line-reference 24 | run: msbuild /m /p:Configuration=${{inputs.build-config}} /p:GitCommit=${{github.sha}} /p:GitBranch=${{github.ref}} ${{inputs.sln-path}} 25 | shell: cmd 26 | 27 | - name: Upload Artifact 28 | if: ${{success()}} 29 | uses: actions/upload-artifact@v4 30 | with: 31 | name: compiled-dll-${{github.sha}} 32 | path: | 33 | ${{inputs.sln-path}}/${{inputs.build-config}}/Phobos.dll 34 | ${{inputs.sln-path}}/${{inputs.build-config}}/Phobos.pdb 35 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | # Maintain dependencies for GitHub Actions 4 | - package-ecosystem: "github-actions" 5 | directory: "/" 6 | schedule: 7 | interval: "monthly" 8 | -------------------------------------------------------------------------------- /.github/labeler.yml: -------------------------------------------------------------------------------- 1 | # https://github.com/marketplace/actions/auto-labeler 2 | # labeler "full" schema 3 | 4 | # enable labeler on issues, prs, or both. 5 | enable: 6 | issues: false 7 | prs: true 8 | # comments object allows you to specify a different message for issues and prs 9 | 10 | # Labels is an object where: 11 | # - keys are labels 12 | # - values are objects of { include: [ pattern ], exclude: [ pattern ] } 13 | # - pattern must be a valid regex, and is applied globally to 14 | # title + description of issues and/or prs (see enabled config above) 15 | # - 'include' patterns will associate a label if any of these patterns match 16 | # - 'exclude' patterns will ignore this label if any of these patterns match 17 | labels: 18 | 'Minor': 19 | include: 20 | - '(?i)\[minor\]' 21 | exclude: [] 22 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 3 | -------------------------------------------------------------------------------- /.github/workflows/labeler-action.yml: -------------------------------------------------------------------------------- 1 | name: Labeler Action 2 | on: 3 | pull_request_target: 4 | types: [opened, edited] 5 | 6 | jobs: 7 | 8 | labeler: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - name: Label 13 | id: labeler 14 | uses: jimschubert/labeler-action@v2 15 | with: 16 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 17 | -------------------------------------------------------------------------------- /.github/workflows/nightly.yml: -------------------------------------------------------------------------------- 1 | name: Nightly Build 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | - main 8 | - develop 9 | 10 | env: 11 | # Path to the solution file relative to the root of the project. 12 | SOLUTION_FILE_PATH: . 13 | 14 | # Configuration type to build. 15 | # You can convert this to a build matrix if you need coverage of multiple configuration types. 16 | # https://docs.github.com/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix 17 | BUILD_CONFIGURATION: DevBuild 18 | # GIT_COMMIT: $(git rev-parse --short "$GITHUB_SHA") 19 | # GIT_BRANCH: ${GITHUB_REF#refs/heads/} 20 | 21 | jobs: 22 | build: 23 | runs-on: windows-2019 24 | 25 | steps: 26 | - uses: actions/checkout@v4 27 | with: 28 | submodules: recursive 29 | 30 | - name: Build Phobos 31 | uses: ./.github/actions/build-phobos # Build steps are reused 32 | with: 33 | sln-path: ${{env.SOLUTION_FILE_PATH}} 34 | build-config: ${{env.BUILD_CONFIGURATION}} 35 | -------------------------------------------------------------------------------- /.github/workflows/pr-nightly.yml: -------------------------------------------------------------------------------- 1 | name: Pull Request Nightly Build 2 | 3 | on: 4 | pull_request: 5 | 6 | env: 7 | # Path to the solution file relative to the root of the project. 8 | SOLUTION_FILE_PATH: . 9 | 10 | # Configuration type to build. 11 | # You can convert this to a build matrix if you need coverage of multiple configuration types. 12 | # https://docs.github.com/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix 13 | BUILD_CONFIGURATION: DevBuild 14 | # GIT_COMMIT: $(git rev-parse --short "$GITHUB_SHA") 15 | # GIT_BRANCH: ${GITHUB_REF#refs/heads/} 16 | 17 | jobs: 18 | build: 19 | runs-on: windows-2019 20 | 21 | steps: 22 | - uses: actions/checkout@v4 23 | with: 24 | submodules: recursive 25 | # ref: ${{ github.event.pull_request.head.sha }} 26 | 27 | - name: Build Phobos 28 | uses: ./.github/actions/build-phobos # Setup steps are reused 29 | with: 30 | sln-path: ${{env.SOLUTION_FILE_PATH}} 31 | build-config: ${{env.BUILD_CONFIGURATION}} 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Release 2 | Debug 3 | *.vcxproj.user 4 | *.vcxproj.filters 5 | *.sdf 6 | *.suo 7 | .vs 8 | .cproject 9 | .project 10 | *.aps 11 | 12 | Nightly/ 13 | 14 | DevBuild/ 15 | 16 | docs/_build/ 17 | docs/locale/.doctrees/ 18 | *.pot 19 | *.mo 20 | 21 | /.vscode/c_cpp_properties.json 22 | /.vscode/cspell.json 23 | /.vscode/settings.json 24 | 25 | build 26 | cmake-* 27 | out 28 | .idea 29 | 30 | # Python virtual environment for docs 31 | .venv/ 32 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "YRpp"] 2 | path = YRpp 3 | url = https://github.com/Phobos-developers/YRpp.git 4 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yaml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | # Set the version of Python and other tools you might need 9 | build: 10 | os: ubuntu-24.04 11 | tools: 12 | python: "3.11" 13 | 14 | # Build documentation in the docs/ directory with Sphinx 15 | sphinx: 16 | configuration: docs/conf.py 17 | 18 | # Optionally build your docs in additional formats such as PDF 19 | formats: 20 | - pdf 21 | 22 | # We recommend specifying your dependencies to enable reproducible builds: 23 | python: 24 | install: 25 | - requirements: docs/requirements.txt 26 | -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.example.json: -------------------------------------------------------------------------------- 1 | { 2 | // This is a Phobos project-specific config file for VSCode official C++ extension. 3 | // https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools 4 | 5 | // Change those variables to match the installation paths 6 | // of the described items in your system. 7 | "env": { 8 | // Path to Visual Studio or VS Build Tools installation folder. 9 | "vsPath": "${env:ProgramFiles(x86)}/Microsoft Visual Studio/2019/Community", 10 | }, 11 | 12 | // Don't change below this line unless you know what you're doing. 13 | "configurations": [ 14 | { 15 | "name": "Win32", 16 | "includePath": [ 17 | "${workspaceFolder}/src", 18 | "${workspaceFolder}/src/**", 19 | "${workspaceFolder}/YRpp", 20 | "${workspaceFolder}/YRpp/**", 21 | "${workspaceFolder}/lib", 22 | "${workspaceFolder}/lib/**", 23 | ], 24 | "defines": [ 25 | "SYR_VER=2", 26 | "HAS_EXCEPTIONS=0", 27 | "NOMINMAX", 28 | "_CRT_SECURE_NO_WARNINGS", 29 | "_WINDLL" 30 | ], 31 | "compilerPath": "${vsPath}/VC/Tools/MSVC/14.29.30133/bin/HostX86/x86/cl.exe", 32 | "windowsSdkVersion": "10.0.20348.0", 33 | "cStandard": "c17", 34 | "cppStandard": "c++20", 35 | "intelliSenseMode": "windows-msvc-x86", 36 | "browse": { 37 | "limitSymbolsToIncludedHeaders": false 38 | } 39 | } 40 | ], 41 | "version": 5 42 | } 43 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. 3 | // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp 4 | 5 | // List of extensions which should be recommended for users of this workspace. 6 | "recommendations": [ 7 | "ms-vscode.cpptools", 8 | "executablebookproject.myst-highlight", 9 | "visualstudioexptteam.vscodeintellicode", 10 | "fernandoescolar.vscode-solution-explorer", 11 | "editorconfig.editorconfig", 12 | "michelemelluso.gitignore", 13 | "spmeesseman.vscode-taskexplorer", 14 | "streetsidesoftware.code-spell-checker", 15 | "gruntfuggly.todo-tree", 16 | "shardulm94.trailing-spaces" 17 | ], 18 | // List of extensions recommended by VS Code that should not be recommended for users of this workspace. 19 | "unwantedRecommendations": ["llvm-vs-code-extensions.vscode-clangd"] 20 | } 21 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Debug current file as memory dump", 6 | "type": "cppvsdbg", 7 | "request": "launch", 8 | "program": "some text to trick VSCode", 9 | "dumpPath": "${file}", 10 | "symbolSearchPath": "${fileDirname};${config:gamemdFolder};${workspaceFolder}/Debug;${config:additionalPdbPaths}" 11 | }, 12 | { 13 | "name": "Attach debugger to Yuri's Revenge", 14 | "type": "cppvsdbg", 15 | "request": "attach", 16 | "program": "${config:gamemdFolder}/gamemd.exe", 17 | "cwd": "${config:gamemdFolder}", 18 | "symbolSearchPath": "${config:gamemdFolder};${workspaceFolder}/Debug;${config:additionalPdbPaths}" 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /.vscode/settings.example.json: -------------------------------------------------------------------------------- 1 | // This is a Phobos project-specific workspace settings file for VSCode. 2 | // Change the variables below to match the paths of the described items in your system. 3 | { 4 | // Path to main Red Alert 2: Yuri's Revenge folder (should contain gamemd.exe). 5 | // Edit to point to correct one, without trailing slash. 6 | "gamemdFolder": "${workspaceFolder}/Debug", 7 | 8 | // List of additional paths (semicolon-separated) to folders where PDBs are located. 9 | // Change if needed, should be correct by default for most recent debug build. 10 | "additionalPdbPaths": "", 11 | 12 | // --------------------------------------------------------------- 13 | // Don't change below this line unless you know what you're doing. 14 | // --------------------------------------------------------------- 15 | 16 | //-------- CPP Extension Configuration -------- 17 | "C_Cpp.errorSquiggles": "Enabled", 18 | 19 | //-------- Task Explorer Configuration -------- 20 | "taskExplorer.exclude": ["**/Phobos/scripts/**", "**/Phobos/docs/**"], 21 | 22 | //-------- Spell Checker Configuration -------- 23 | "cSpell.language": "en", 24 | "cSpell.enabledLanguageIds": ["markdown", "plaintext", "yml", "cpp"], 25 | "cSpell.allowCompoundWords": true, 26 | "cSpell.ignorePaths": [ 27 | "vscode-extension", 28 | ".git", 29 | "*.dll", 30 | "**/*.dll", 31 | "*.pdb", 32 | "**/*.pdb", 33 | "*.lib", 34 | "**/*.lib" 35 | ], 36 | "cSpell.diagnosticLevel": "Hint" 37 | } 38 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "Build Phobos debug build", 8 | "type": "process", 9 | "command": [], 10 | "windows": { 11 | "command": "scripts/build_debug.bat" 12 | }, 13 | "group": { 14 | "kind": "build", 15 | "isDefault": true 16 | }, 17 | "problemMatcher": "$msCompile" 18 | }, 19 | { 20 | "label": "Build Phobos development build", 21 | "type": "process", 22 | "command": [], 23 | "windows": { 24 | "command": "scripts/build_devbuild.bat" 25 | }, 26 | "group": "build", 27 | "problemMatcher": "$msCompile" 28 | }, 29 | { 30 | "label": "Build Phobos release build", 31 | "type": "process", 32 | "command": [], 33 | "windows": { 34 | "command": "scripts/build_release.bat" 35 | }, 36 | "group": "build", 37 | "problemMatcher": "$msCompile" 38 | }, 39 | { 40 | "label": "Build Phobos docs with Sphinx", 41 | "type": "process", 42 | "command": [], 43 | "windows": { 44 | "command": "scripts/build_docs.bat" 45 | }, 46 | "group": "build", 47 | "problemMatcher": [] 48 | }, 49 | { 50 | "label": "Build Phobos locale files of zh_CN", 51 | "type": "process", 52 | "command": [], 53 | "windows": { 54 | "command": "scripts/build_docs_locale.bat" 55 | }, 56 | "group": "build", 57 | "problemMatcher": [] 58 | }, 59 | { 60 | "label": "Cleanup build folders", 61 | "type": "process", 62 | "command": [], 63 | "windows": { 64 | "command": "scripts/clean.bat" 65 | }, 66 | "group": "none", 67 | "problemMatcher": [] 68 | }, 69 | { 70 | "label": "Setup VSCode C++ extension initial configuration", 71 | "type": "process", 72 | "command": [], 73 | "windows": { 74 | "command": "scripts/configure_vscode_cpp.bat" 75 | }, 76 | "group": "none", 77 | "problemMatcher": [], 78 | "runOptions": { 79 | "runOn": "folderOpen" 80 | }, 81 | "presentation": { 82 | "echo": false, 83 | "reveal": "never", 84 | "panel": "shared", 85 | "showReuseMessage": false 86 | } 87 | } 88 | ] 89 | } 90 | -------------------------------------------------------------------------------- /.vsconfig: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0", 3 | "components": [ 4 | "Microsoft.VisualStudio.Component.CoreEditor", 5 | "Microsoft.VisualStudio.Workload.CoreEditor", 6 | "Microsoft.VisualStudio.Component.VC.CoreIde", 7 | "Microsoft.VisualStudio.Component.Windows10SDK.20348", 8 | "Microsoft.VisualStudio.Component.VC.14.29.16.11.x86.x64", 9 | "Microsoft.VisualStudio.Component.VC.14.29.16.11.ATL" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /Phobos.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29209.62 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Phobos", "Phobos.vcxproj", "{3FAF7126-F38C-4D1E-9973-C21A37870F60}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x86 = Debug|x86 11 | DevBuild|x86 = DevBuild|x86 12 | Release|x86 = Release|x86 13 | EndGlobalSection 14 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 15 | {3FAF7126-F38C-4D1E-9973-C21A37870F60}.Debug|x86.ActiveCfg = Debug|Win32 16 | {3FAF7126-F38C-4D1E-9973-C21A37870F60}.Debug|x86.Build.0 = Debug|Win32 17 | {3FAF7126-F38C-4D1E-9973-C21A37870F60}.DevBuild|x86.ActiveCfg = DevBuild|Win32 18 | {3FAF7126-F38C-4D1E-9973-C21A37870F60}.DevBuild|x86.Build.0 = DevBuild|Win32 19 | {3FAF7126-F38C-4D1E-9973-C21A37870F60}.Release|x86.ActiveCfg = Release|Win32 20 | {3FAF7126-F38C-4D1E-9973-C21A37870F60}.Release|x86.Build.0 = Release|Win32 21 | EndGlobalSection 22 | GlobalSection(SolutionProperties) = preSolution 23 | HideSolutionNode = FALSE 24 | EndGlobalSection 25 | GlobalSection(ExtensibilityGlobals) = postSolution 26 | SolutionGuid = {6CFF9E33-BCA4-46D8-A824-72F4C3242D5A} 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /docs/CREDITS.md: -------------------------------------------------------------------------------- 1 | ```{include} ../CREDITS.md 2 | :relative-docs: docs/ 3 | :relative-images: 4 | ``` 5 | -------------------------------------------------------------------------------- /docs/License.md: -------------------------------------------------------------------------------- 1 | # License 2 | 3 | ```{include} ../LICENSE.md 4 | :relative-docs: docs/ 5 | :relative-images: 6 | ``` 7 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/_static/icons/auto.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/_static/icons/dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /docs/_static/icons/light.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /docs/_static/icons/status.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/_static/images/VoxelLightSourceComparison.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/VoxelLightSourceComparison.png -------------------------------------------------------------------------------- /docs/_static/images/animToUnit.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/animToUnit.gif -------------------------------------------------------------------------------- /docs/_static/images/buildingQueue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/buildingQueue.png -------------------------------------------------------------------------------- /docs/_static/images/cust-Chrono.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/cust-Chrono.gif -------------------------------------------------------------------------------- /docs/_static/images/digital_display_shapes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/digital_display_shapes.png -------------------------------------------------------------------------------- /docs/_static/images/disklaser-radius-values-01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/disklaser-radius-values-01.gif -------------------------------------------------------------------------------- /docs/_static/images/ebolt.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/ebolt.gif -------------------------------------------------------------------------------- /docs/_static/images/feedbackweapon.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/feedbackweapon.gif -------------------------------------------------------------------------------- /docs/_static/images/forceweapon_emp.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/forceweapon_emp.gif -------------------------------------------------------------------------------- /docs/_static/images/grinding.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/grinding.gif -------------------------------------------------------------------------------- /docs/_static/images/hackerfinallyworks-01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/hackerfinallyworks-01.gif -------------------------------------------------------------------------------- /docs/_static/images/harvestercounter-01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/harvestercounter-01.gif -------------------------------------------------------------------------------- /docs/_static/images/healthbar.hide-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/healthbar.hide-01.png -------------------------------------------------------------------------------- /docs/_static/images/initialstrength.cloning-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/initialstrength.cloning-01.png -------------------------------------------------------------------------------- /docs/_static/images/issinglecolor.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/issinglecolor.gif -------------------------------------------------------------------------------- /docs/_static/images/jumpjet-tilt.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/jumpjet-tilt.gif -------------------------------------------------------------------------------- /docs/_static/images/jumpjet-turning.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/jumpjet-turning.gif -------------------------------------------------------------------------------- /docs/_static/images/lasertrails.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/lasertrails.gif -------------------------------------------------------------------------------- /docs/_static/images/lowpriority-01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/lowpriority-01.gif -------------------------------------------------------------------------------- /docs/_static/images/mindcontrol-max-range-01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/mindcontrol-max-range-01.gif -------------------------------------------------------------------------------- /docs/_static/images/mindcontrol-multiple-01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/mindcontrol-multiple-01.gif -------------------------------------------------------------------------------- /docs/_static/images/objectinfo-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/objectinfo-01.png -------------------------------------------------------------------------------- /docs/_static/images/ore-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/ore-01.png -------------------------------------------------------------------------------- /docs/_static/images/oregath.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/oregath.gif -------------------------------------------------------------------------------- /docs/_static/images/placepreview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/placepreview.png -------------------------------------------------------------------------------- /docs/_static/images/powerdelta-01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/powerdelta-01.gif -------------------------------------------------------------------------------- /docs/_static/images/powersup.owner-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/powersup.owner-01.png -------------------------------------------------------------------------------- /docs/_static/images/preserve-ic.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/preserve-ic.gif -------------------------------------------------------------------------------- /docs/_static/images/producing-progress-01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/producing-progress-01.gif -------------------------------------------------------------------------------- /docs/_static/images/projectile-interception-01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/projectile-interception-01.gif -------------------------------------------------------------------------------- /docs/_static/images/promotedspawns-01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/promotedspawns-01.gif -------------------------------------------------------------------------------- /docs/_static/images/radtype-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/radtype-01.png -------------------------------------------------------------------------------- /docs/_static/images/remember-target-after-deploying-01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/remember-target-after-deploying-01.gif -------------------------------------------------------------------------------- /docs/_static/images/remove-mc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/remove-mc.gif -------------------------------------------------------------------------------- /docs/_static/images/shrapnel.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/shrapnel.gif -------------------------------------------------------------------------------- /docs/_static/images/spawnrange-01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/spawnrange-01.gif -------------------------------------------------------------------------------- /docs/_static/images/splashlist-01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/splashlist-01.gif -------------------------------------------------------------------------------- /docs/_static/images/strafing-01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/strafing-01.gif -------------------------------------------------------------------------------- /docs/_static/images/straight.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/straight.gif -------------------------------------------------------------------------------- /docs/_static/images/sw_sidebar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/sw_sidebar.png -------------------------------------------------------------------------------- /docs/_static/images/swnext.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/swnext.gif -------------------------------------------------------------------------------- /docs/_static/images/technoshield-01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/technoshield-01.gif -------------------------------------------------------------------------------- /docs/_static/images/tooltips-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/tooltips-01.png -------------------------------------------------------------------------------- /docs/_static/images/translucency-fix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/translucency-fix.png -------------------------------------------------------------------------------- /docs/_static/images/tree-shake.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/tree-shake.gif -------------------------------------------------------------------------------- /docs/_static/images/turretoffset-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/turretoffset-01.png -------------------------------------------------------------------------------- /docs/_static/images/underwater-new-attack-tag.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/underwater-new-attack-tag.gif -------------------------------------------------------------------------------- /docs/_static/images/weaponfilter.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/docs/_static/images/weaponfilter.gif -------------------------------------------------------------------------------- /docs/_static/js/ini-block-maker.js: -------------------------------------------------------------------------------- 1 | // Create an INI code block with given `newId` as a child of `parent` node, with an optional `height` 2 | function makeINICodeBlock(parent, newId, height) { 3 | let div1 = document.createElement("div"); 4 | div1.className = "highlight-ini notranslate"; 5 | if (height != null) { 6 | div1.style.height = `${height}px`; 7 | div1.style.overflow = "auto"; 8 | } 9 | let div2 = document.createElement("div"); 10 | div2.className = "highlight"; 11 | let pre = document.createElement("pre"); 12 | pre.id = newId; 13 | div2.appendChild(pre); 14 | div1.appendChild(div2); 15 | parent.appendChild(div1); 16 | } 17 | 18 | // Add an INI line to a code block node (a direct parent
 node)
19 | // An INI line consists of a `key`, `value` and `comment`, all can be null
20 | function addINILine(codeBlockNode, line) {
21 | 	if (line.key != null) {
22 | 		let na = document.createElement("span");
23 | 		na.className = "na";
24 | 		na.textContent = line.key;
25 | 		codeBlockNode.appendChild(na);
26 | 		let o = document.createElement("span");
27 | 		o.className = "o";
28 | 		o.textContent = "=";
29 | 		codeBlockNode.appendChild(o);
30 | 	}
31 | 	if (line.value != null) {
32 | 		let s = document.createElement("span");
33 | 		s.className = "s";
34 | 		s.textContent = line.value;
35 | 		codeBlockNode.appendChild(s);
36 | 	}
37 | 	if (line.comment != null) {
38 | 		if (line.key != null || line.value != null) {
39 | 			let w = document.createElement("span");
40 | 			w.className = "w";
41 | 			w.textContent = ' ';
42 | 			codeBlockNode.appendChild(w);
43 | 		}
44 | 		let c1 = document.createElement("span");
45 | 		c1.className = "c1";
46 | 		c1.textContent = line.comment;
47 | 		codeBlockNode.appendChild(c1);
48 | 	}
49 | 	let w = document.createElement("span");
50 | 	w.className = "w";
51 | 	w.textContent = '\n';
52 | 	codeBlockNode.appendChild(w);
53 | }
54 | 


--------------------------------------------------------------------------------
/docs/_templates/layout.html:
--------------------------------------------------------------------------------
 1 | {% extends "!layout.html" %}
 2 | {% block extrahead %}
 3 |   {{ super() }}
 4 |   
 5 |   
 6 |   
 7 |   
 8 |   
 9 | {% endblock %}
10 | 
11 | {% block footer %}
12 |     
13 | {% endblock %}
14 | 


--------------------------------------------------------------------------------
/docs/conf.py:
--------------------------------------------------------------------------------
 1 | # Configuration file for the Sphinx documentation builder.
 2 | #
 3 | # This file only contains a selection of the most common options. For a full
 4 | # list see the documentation:
 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html
 6 | 
 7 | # -- Path setup --------------------------------------------------------------
 8 | 
 9 | # If extensions (or modules to document with autodoc) are in another directory,
10 | # add these directories to sys.path here. If the directory is relative to the
11 | # documentation root, use os.path.abspath to make it absolute, like shown here.
12 | #
13 | # import os
14 | # import sys
15 | # sys.path.insert(0, os.path.abspath('.'))
16 | 
17 | 
18 | # -- Project information -----------------------------------------------------
19 | 
20 | project = 'Phobos'
21 | copyright = '2025, The Phobos Contributors'
22 | author = 'The Phobos Contributors'
23 | 
24 | # -- General configuration ---------------------------------------------------
25 | 
26 | # Add any Sphinx extension module names here, as strings. They can be
27 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
28 | # ones.
29 | extensions = ['sphinx_rtd_theme', 'myst_parser', 'sphinx.ext.mathjax', 'sphinx_design']
30 | 
31 | # Add any paths that contain templates here, relative to this directory.
32 | templates_path = ['_templates']
33 | 
34 | # List of patterns, relative to source directory, that match files and
35 | # directories to ignore when looking for source files.
36 | # This pattern also affects html_static_path and html_extra_path.
37 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
38 | 
39 | locale_dirs = ['locale/']
40 | gettext_compact = False
41 | gettext_additional_targets = ["literal-block"]
42 | 
43 | # -- Options for HTML output -------------------------------------------------
44 | 
45 | # The theme to use for HTML and HTML Help pages.  See the documentation for
46 | # a list of builtin themes.
47 | #
48 | html_theme = 'sphinx_rtd_theme'
49 | 
50 | # Add any paths that contain custom static files (such as style sheets) here,
51 | # relative to this directory. They are copied after the builtin static files,
52 | # so a file named "default.css" will overwrite the builtin "default.css".
53 | html_static_path = ['_static']
54 | 
55 | myst_heading_anchors = 3
56 | 
57 | myst_enable_extensions = [
58 |     "amsmath",
59 |     "dollarmath",
60 |     "colon_fence",
61 | ]
62 | 
63 | html_theme_options = {
64 |     'navigation_depth': 4,
65 | }
66 | 


--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
 1 | ```{toctree}
 2 | :hidden:
 3 | :caption: Project Info
 4 | General Info
 5 | What's New
 6 | Contributing
 7 | Credits
 8 | License
 9 | ```
10 | 
11 | ```{toctree}
12 | :hidden:
13 | :caption: Extension Documentation
14 | New / Enhanced Logics
15 | Fixed / Improved Logics
16 | AI Scripting and Mapping
17 | User Interface
18 | Miscellanous
19 | ```
20 | 
21 | ```{include} ../README.md
22 | :relative-docs: docs/
23 | :relative-images:
24 | ```
25 | 


--------------------------------------------------------------------------------
/docs/make.bat:
--------------------------------------------------------------------------------
 1 | @ECHO OFF
 2 | 
 3 | pushd %~dp0
 4 | 
 5 | REM Command file for Sphinx documentation
 6 | 
 7 | if "%SPHINXBUILD%" == "" (
 8 | 	set SPHINXBUILD=sphinx-build
 9 | )
10 | set SOURCEDIR=.
11 | set BUILDDIR=_build
12 | 
13 | if "%1" == "" goto help
14 | 
15 | %SPHINXBUILD% >NUL 2>NUL
16 | if errorlevel 9009 (
17 | 	echo.
18 | 	echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
19 | 	echo.installed, then set the SPHINXBUILD environment variable to point
20 | 	echo.to the full path of the 'sphinx-build' executable. Alternatively you
21 | 	echo.may add the Sphinx directory to PATH.
22 | 	echo.
23 | 	echo.If you don't have Sphinx installed, grab it from
24 | 	echo.http://sphinx-doc.org/
25 | 	exit /b 1
26 | )
27 | 
28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
29 | goto end
30 | 
31 | :help
32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
33 | 
34 | :end
35 | popd
36 | 


--------------------------------------------------------------------------------
/docs/requirements.txt:
--------------------------------------------------------------------------------
1 | myst-parser==4.0.0
2 | Sphinx==7.4.7
3 | sphinx-rtd-theme==2.0.0
4 | sphinx-design==0.6.1
5 | 


--------------------------------------------------------------------------------
/images/ChrisLv-relicense.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/images/ChrisLv-relicense.png


--------------------------------------------------------------------------------
/lib/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 | 


--------------------------------------------------------------------------------
/logo-mono.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/logo-mono.png


--------------------------------------------------------------------------------
/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/logo.png


--------------------------------------------------------------------------------
/scripts/build_debug.bat:
--------------------------------------------------------------------------------
1 | @if not defined _echo echo off
2 | 
3 | rem Builds Phobos DevBuild.
4 | 
5 | rem Ensure we're in correct directory.
6 | cd /D "%~dp0"
7 | 
8 | call run_msbuild /maxCpuCount /consoleloggerparameters:NoSummary /property:Configuration=Debug
9 | 


--------------------------------------------------------------------------------
/scripts/build_devbuild.bat:
--------------------------------------------------------------------------------
1 | @if not defined _echo echo off
2 | 
3 | rem Builds Phobos DevBuild.
4 | 
5 | rem Ensure we're in correct directory.
6 | cd /D "%~dp0"
7 | 
8 | call run_msbuild /maxCpuCount /consoleloggerparameters:NoSummary /property:Configuration=DevBuild
9 | 


--------------------------------------------------------------------------------
/scripts/build_docs.bat:
--------------------------------------------------------------------------------
 1 | @if not defined _echo echo off
 2 | 
 3 | rem Builds Phobos docs with Sphinx.
 4 | 
 5 | rem Ensure we're in correct directory.
 6 | cd /D "%~dp0"
 7 | cd ..\docs
 8 | 
 9 | call make.bat html
10 | 


--------------------------------------------------------------------------------
/scripts/build_docs_locale.bat:
--------------------------------------------------------------------------------
 1 | @if not defined _echo echo off
 2 | 
 3 | rem Builds Phobos docs with Sphinx.
 4 | 
 5 | rem Ensure we're in correct directory.
 6 | cd /D "%~dp0"
 7 | cd ..\docs
 8 | 
 9 | sphinx-build -b gettext ./ ./locale
10 | sphinx-intl update -p ./locale -l zh_CN
11 | 


--------------------------------------------------------------------------------
/scripts/build_release.bat:
--------------------------------------------------------------------------------
1 | @if not defined _echo echo off
2 | 
3 | rem Builds Phobos Release.
4 | 
5 | rem Ensure we're in correct directory.
6 | cd /D "%~dp0"
7 | 
8 | call run_msbuild /maxCpuCount /consoleloggerparameters:NoSummary /property:Configuration=Release
9 | 


--------------------------------------------------------------------------------
/scripts/clean.bat:
--------------------------------------------------------------------------------
 1 | @if not defined _echo echo off
 2 | 
 3 | rem Cleans build folders.
 4 | 
 5 | rem Ensure we're in correct directory.
 6 | cd /D "%~dp0"
 7 | cd ..
 8 | 
 9 | if exist Debug\ rmdir /S /Q Debug\
10 | if exist DevBuild\ rmdir /S /Q DevBuild\
11 | if exist Release\ rmdir /S /Q Release\
12 | 


--------------------------------------------------------------------------------
/scripts/configure_vscode_cpp.bat:
--------------------------------------------------------------------------------
 1 | @if not defined _echo echo off
 2 | 
 3 | rem Copies and opens example config files for VSCode.
 4 | 
 5 | rem Ensure we're in correct directory.
 6 | cd /D "%~dp0"
 7 | cd ..\.vscode\
 8 | 
 9 | if exist c_cpp_properties.json (
10 |     echo C++ extension configuration file already present, skipping.
11 | ) else (
12 |     copy c_cpp_properties.example.json c_cpp_properties.json
13 |     code c_cpp_properties.json
14 | )
15 | 
16 | if exist settings.json (
17 |     echo Settings configuration file already present, skipping.
18 | ) else (
19 |     copy settings.example.json settings.json
20 |     code settings.json
21 | )
22 | 


--------------------------------------------------------------------------------
/scripts/run_msbuild.bat:
--------------------------------------------------------------------------------
1 | @if not defined _echo echo off
2 | 
3 | rem Executes MSBuild found using VS Locator and VS Dev. Cmd. Prompt.
4 | 
5 | rem Ensure we're in correct directory.
6 | cd /D "%~dp0"
7 | 
8 | run_vsdevcmd.bat & cd .. & msbuild %*
9 | 


--------------------------------------------------------------------------------
/scripts/run_vsdevcmd.bat:
--------------------------------------------------------------------------------
 1 | @if not defined _echo echo off
 2 | 
 3 | rem Finds and starts Visual Studio Developer Command Prompt using VS Locator.
 4 | rem https://github.com/microsoft/vswhere/wiki/Start-Developer-Command-Prompt
 5 | 
 6 | rem Ensure we're in correct directory.
 7 | cd /D "%~dp0"
 8 | 
 9 | for /f "usebackq delims=" %%i in (`vswhere.exe -products * -prerelease -latest -property installationPath`) do (
10 |   if exist "%%i\Common7\Tools\vsdevcmd.bat" (
11 |     call "%%i\Common7\Tools\vsdevcmd.bat" %*
12 |     exit /b
13 |   )
14 | )
15 | 
16 | echo VS Locator is unable to locate Visual Studio Developer Command Prompt. Ensure you have VS or VS Build Tools installed.
17 | exit /b 2
18 | 


--------------------------------------------------------------------------------
/scripts/vswhere.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/scripts/vswhere.exe


--------------------------------------------------------------------------------
/src/Blowfish/Hooks.Blowfish.cpp:
--------------------------------------------------------------------------------
 1 | #include "blowfish.h"
 2 | #include 
 3 | #include 
 4 | 
 5 | /**
 6 |  *  Remove the requirement for BLOWFISH.DLL (Blowfish encryption) and now
 7 |  *  handle the encryption/decryption internally.
 8 |  *
 9 |  *  @author: ZivDero
10 |  */
11 | 
12 | /**
13 |  *  Skip loading BLOWFISH.DLL
14 |  */
15 | DEFINE_JUMP(LJMP, 0x6BC33A, 0x6BC425);
16 | DEFINE_JUMP(LJMP, 0x6BD6CA, 0x6BD71D);
17 | 
18 | /**
19 |  *  Replace BlowfishEngine functions.
20 |  */
21 | DEFINE_FUNCTION_JUMP(LJMP, 0x437FC0, BlowfishEngine::~BlowfishEngine);
22 | DEFINE_FUNCTION_JUMP(LJMP, 0x437FD0, BlowfishEngine::Submit_Key);
23 | DEFINE_FUNCTION_JUMP(LJMP, 0x438000, BlowfishEngine::Encrypt);
24 | DEFINE_FUNCTION_JUMP(LJMP, 0x438030, BlowfishEngine::Decrypt);
25 | 
26 | /**
27 |  *  gamemd.exe contains a COM proxy for the actual BlowfishEngine class.
28 |  *  As a consequence, we need to replace the memory allocations in BlowPipe and
29 |  *  BlowStraw, because by default they only allocate 4 bytes.
30 |  */
31 | DEFINE_HOOK(0x4381DA, BlowPipe_Key_BlowfishEngine_Allocation, 0x0)
32 | {
33 | 	BlowfishEngine* bf = GameCreate();
34 | 	R->EAX(bf);
35 | 	return 0x4381F3;
36 | }
37 | 
38 | DEFINE_HOOK(0x43830A, BlowStraw_Key_BlowfishEngine_Allocation, 0x0)
39 | {
40 | 	BlowfishEngine* bf = GameCreate();
41 | 	R->EAX(bf);
42 | 	return 0x438323;
43 | }
44 | 


--------------------------------------------------------------------------------
/src/Commands/Commands.cpp:
--------------------------------------------------------------------------------
 1 | #include 
 2 | #include "Commands.h"
 3 | 
 4 | #include "ObjectInfo.h"
 5 | #include "NextIdleHarvester.h"
 6 | #include "QuickSave.h"
 7 | #include "DamageDisplay.h"
 8 | #include "FrameByFrame.h"
 9 | #include "FrameStep.h"
10 | #include "ToggleDigitalDisplay.h"
11 | #include "ToggleDesignatorRange.h"
12 | #include "SaveVariablesToFile.h"
13 | #include "ToggleSWSidebar.h"
14 | #include "FireTacticalSW.h"
15 | #include 
16 | 
17 | DEFINE_HOOK(0x533066, CommandClassCallback_Register, 0x6)
18 | {
19 | 	// Load it after Ares'
20 | 
21 | 	MakeCommand();
22 | 	MakeCommand();
23 | 	MakeCommand();
24 | 	MakeCommand();
25 | 	MakeCommand();
26 | 
27 | 	if (Phobos::Config::SuperWeaponSidebarCommands)
28 | 	{
29 | 		SWSidebarClass::Commands[0] = MakeCommand>();
30 | 		SWSidebarClass::Commands[1] = MakeCommand>();
31 | 		SWSidebarClass::Commands[2] = MakeCommand>();
32 | 		SWSidebarClass::Commands[3] = MakeCommand>();
33 | 		SWSidebarClass::Commands[4] = MakeCommand>();
34 | 		SWSidebarClass::Commands[5] = MakeCommand>();
35 | 		SWSidebarClass::Commands[6] = MakeCommand>();
36 | 		SWSidebarClass::Commands[7] = MakeCommand>();
37 | 		SWSidebarClass::Commands[8] = MakeCommand>();
38 | 		SWSidebarClass::Commands[9] = MakeCommand>();
39 | 	}
40 | 
41 | 	if (Phobos::Config::DevelopmentCommands)
42 | 	{
43 | 		MakeCommand();
44 | 		MakeCommand();
45 | 		MakeCommand();
46 | 		MakeCommand();
47 | 		MakeCommand>(); // Single step in
48 | 		MakeCommand>(); // Speed 1
49 | 		MakeCommand>(); // Speed 2
50 | 		MakeCommand>(); // Speed 3
51 | 		MakeCommand>(); // Speed 4
52 | 		MakeCommand>(); // Speed 5
53 | 	}
54 | 
55 | 	return 0;
56 | }
57 | 


--------------------------------------------------------------------------------
/src/Commands/Commands.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | 
 3 | #include 
 4 | #include 
 5 | #include 
 6 | #include 
 7 | #include 
 8 | 
 9 | template 
10 | T* MakeCommand()
11 | {
12 | 	T* command = GameCreate();
13 | 	CommandClass::Array.AddItem(command);
14 | 	return command;
15 | };
16 | 
17 | #define CATEGORY_TEAM StringTable::LoadString(GameStrings::TXT_TEAM)
18 | #define CATEGORY_INTERFACE StringTable::LoadString(GameStrings::TXT_INTERFACE)
19 | #define CATEGORY_TAUNT StringTable::LoadString(GameStrings::TXT_TAUNT)
20 | #define CATEGORY_SELECTION StringTable::LoadString(GameStrings::TXT_SELECTION)
21 | #define CATEGORY_CONTROL StringTable::LoadString(GameStrings::TXT_CONTROL)
22 | #define CATEGORY_DEBUG L"Debug"
23 | #define CATEGORY_GUIDEBUG StringTable::LoadString(GameStrings::GUI_DEBUG)
24 | #define CATEGORY_DEVELOPMENT StringTable::LoadString("TXT_DEVELOPMENT")
25 | 


--------------------------------------------------------------------------------
/src/Commands/DamageDisplay.cpp:
--------------------------------------------------------------------------------
 1 | #include "DamageDisplay.h"
 2 | 
 3 | #include 
 4 | #include 
 5 | 
 6 | const char* DamageDisplayCommandClass::GetName() const
 7 | {
 8 | 	return "Display Damage Numbers";
 9 | }
10 | 
11 | const wchar_t* DamageDisplayCommandClass::GetUIName() const
12 | {
13 | 	return GeneralUtils::LoadStringUnlessMissing("TXT_DISPLAY_DAMAGE", L"Display Damage Dealt");
14 | }
15 | 
16 | const wchar_t* DamageDisplayCommandClass::GetUICategory() const
17 | {
18 | 	return CATEGORY_DEVELOPMENT;
19 | }
20 | 
21 | const wchar_t* DamageDisplayCommandClass::GetUIDescription() const
22 | {
23 | 	return GeneralUtils::LoadStringUnlessMissing("TXT_DISPLAY_DAMAGE_DESC", L"Display exact number of damage dealt to units & buildings on them.");
24 | }
25 | 
26 | void DamageDisplayCommandClass::Execute(WWKey eInput) const
27 | {
28 | 	Phobos::DisplayDamageNumbers = !Phobos::DisplayDamageNumbers;
29 | }
30 | 


--------------------------------------------------------------------------------
/src/Commands/DamageDisplay.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | 
 3 | #include "Commands.h"
 4 | 
 5 | // Display damage strings
 6 | class DamageDisplayCommandClass : public CommandClass
 7 | {
 8 | public:
 9 | 	virtual const char* GetName() const override;
10 | 	virtual const wchar_t* GetUIName() const override;
11 | 	virtual const wchar_t* GetUICategory() const override;
12 | 	virtual const wchar_t* GetUIDescription() const override;
13 | 	virtual void Execute(WWKey eInput) const override;
14 | };
15 | 


--------------------------------------------------------------------------------
/src/Commands/Dummy.cpp:
--------------------------------------------------------------------------------
 1 | #include "Dummy.h"
 2 | 
 3 | #include 
 4 | 
 5 | const char* DummyCommandClass::GetName() const
 6 | {
 7 | 	return "Phobos Dummy";
 8 | }
 9 | 
10 | const wchar_t* DummyCommandClass::GetUIName() const
11 | {
12 | 	return L"Phobos Dummy";
13 | }
14 | 
15 | const wchar_t* DummyCommandClass::GetUICategory() const
16 | {
17 | 	return CATEGORY_DEVELOPMENT
18 | }
19 | 
20 | const wchar_t* DummyCommandClass::GetUIDescription() const
21 | {
22 | 	return L"Dummy";
23 | }
24 | 
25 | void DummyCommandClass::Execute(WWKey eInput) const
26 | {
27 | 	Debug::Log("[Phobos] Dummy command runs.\n");
28 | 	MessageListClass::Instance.PrintMessage(L"[Phobos] Dummy command runs.");
29 | }
30 | 


--------------------------------------------------------------------------------
/src/Commands/Dummy.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | 
 3 | #include "Commands.h"
 4 | 
 5 | // The example command class
 6 | class DummyCommandClass : public CommandClass
 7 | {
 8 | public:
 9 | 	// CommandClass
10 | 	virtual const char* GetName() const override;
11 | 	virtual const wchar_t* GetUIName() const override;
12 | 	virtual const wchar_t* GetUICategory() const override;
13 | 	virtual const wchar_t* GetUIDescription() const override;
14 | 	virtual void Execute(WWKey eInput) const override;
15 | };
16 | 


--------------------------------------------------------------------------------
/src/Commands/FireTacticalSW.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | #include "Commands.h"
 3 | 
 4 | #include 
 5 | #include 
 6 | 
 7 | template
 8 | class FireTacticalSWCommandClass : public CommandClass
 9 | {
10 | 	virtual const char* GetName() const override;
11 | 	virtual const wchar_t* GetUIName() const override;
12 | 	virtual const wchar_t* GetUICategory() const override;
13 | 	virtual const wchar_t* GetUIDescription() const override;
14 | 	virtual void Execute(WWKey eInput) const override;
15 | };
16 | 
17 | template
18 | inline const char* FireTacticalSWCommandClass::GetName() const
19 | {
20 | 	_snprintf_s(Phobos::readBuffer, Phobos::readLength, "FireTacticalSW%d", Index + 1);
21 | 	return Phobos::readBuffer;
22 | }
23 | 
24 | template
25 | inline const wchar_t* FireTacticalSWCommandClass::GetUIName() const
26 | {
27 | 	const wchar_t* csfString = StringTable::TryFetchString("TXT_FIRE_TACTICAL_SW_XX", L"Fire Super Weapon %d");
28 | 	_snwprintf_s(Phobos::wideBuffer, std::size(Phobos::wideBuffer), csfString, Index + 1);
29 | 	return Phobos::wideBuffer;
30 | }
31 | 
32 | template
33 | inline const wchar_t* FireTacticalSWCommandClass::GetUICategory() const
34 | {
35 | 	return CATEGORY_INTERFACE;
36 | }
37 | 
38 | template
39 | inline const wchar_t* FireTacticalSWCommandClass::GetUIDescription() const
40 | {
41 | 	const wchar_t* csfString = StringTable::TryFetchString("TXT_FIRE_TACTICAL_SW_XX_DESC", L"Fires the Super Weapon at position %d in the Super Weapon sidebar.");
42 | 	_snwprintf_s(Phobos::wideBuffer, std::size(Phobos::wideBuffer), csfString, Index + 1);
43 | 	return Phobos::wideBuffer;
44 | }
45 | 
46 | template
47 | inline void FireTacticalSWCommandClass::Execute(WWKey eInput) const
48 | {
49 | 	if (!SWSidebarClass::IsEnabled())
50 | 		return;
51 | 
52 | 	const auto& columns = SWSidebarClass::Instance.Columns;
53 | 
54 | 	if (columns.empty())
55 | 		return;
56 | 
57 | 	const auto& buttons = columns.front()->Buttons;
58 | 
59 | 	if (Index < buttons.size())
60 | 		buttons[Index]->LaunchSuper();
61 | }
62 | 


--------------------------------------------------------------------------------
/src/Commands/FrameByFrame.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | 
 3 | #include "Commands.h"
 4 | 
 5 | class FrameByFrameCommandClass : public CommandClass
 6 | {
 7 | public:
 8 | 	static size_t FrameStepCount;
 9 | 	static bool FrameStep;
10 | 
11 | 	virtual const char* GetName() const override;
12 | 	virtual const wchar_t* GetUIName() const override;
13 | 	virtual const wchar_t* GetUICategory() const override;
14 | 	virtual const wchar_t* GetUIDescription() const override;
15 | 	virtual void Execute(WWKey eInput) const override;
16 | 
17 | 	static bool FrameStepMainLoop();
18 | };
19 | 


--------------------------------------------------------------------------------
/src/Commands/FrameStep.cpp:
--------------------------------------------------------------------------------
1 | #include "FrameStep.h"
2 | 


--------------------------------------------------------------------------------
/src/Commands/FrameStep.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | 
 3 | #include "Commands.h"
 4 | 
 5 | #include "FrameByFrame.h"
 6 | 
 7 | template
 8 | class FrameStepCommandClass : public CommandClass
 9 | {
10 | 	virtual const char* GetName() const override;
11 | 	virtual const wchar_t* GetUIName() const override;
12 | 	virtual const wchar_t* GetUICategory() const override;
13 | 	virtual const wchar_t* GetUIDescription() const override;
14 | 	virtual void Execute(WWKey eInput) const override;
15 | };
16 | 
17 | template
18 | inline const char* FrameStepCommandClass::GetName() const
19 | {
20 | 	_snprintf_s(Phobos::readBuffer, Phobos::readLength, "Step%dFrames", Frame);
21 | 	return Phobos::readBuffer;
22 | }
23 | 
24 | template
25 | inline const wchar_t* FrameStepCommandClass::GetUIName() const
26 | {
27 | 	const wchar_t* csfString = StringTable::TryFetchString("TXT_STEP_XX_FORWARD", L"Step Forward %d Frames");
28 | 	_snwprintf_s(Phobos::wideBuffer, std::size(Phobos::wideBuffer), csfString, Frame);
29 | 	return Phobos::wideBuffer;
30 | }
31 | 
32 | template
33 | inline const wchar_t* FrameStepCommandClass::GetUICategory() const
34 | {
35 | 	return CATEGORY_DEVELOPMENT;
36 | }
37 | 
38 | template
39 | inline const wchar_t* FrameStepCommandClass::GetUIDescription() const
40 | {
41 | 	const wchar_t* csfString = StringTable::TryFetchString("TXT_STEP_XX_FORWARD_DESC", L"Frame Step Only: Step forward %d frames.");
42 | 	_snwprintf_s(Phobos::wideBuffer, std::size(Phobos::wideBuffer), csfString, Frame);
43 | 	return Phobos::wideBuffer;
44 | }
45 | 
46 | template
47 | inline void FrameStepCommandClass::Execute(WWKey eInput) const
48 | {
49 | 	if (!FrameByFrameCommandClass::FrameStep)
50 | 		return;
51 | 
52 | 	Debug::LogAndMessage("Stepping %d frames...\n", Frame);
53 | 
54 | 	FrameByFrameCommandClass::FrameStepCount = Frame;
55 | }
56 | 


--------------------------------------------------------------------------------
/src/Commands/NextIdleHarvester.cpp:
--------------------------------------------------------------------------------
 1 | #include "NextIdleHarvester.h"
 2 | 
 3 | #include 
 4 | #include 
 5 | #include 
 6 | #include 
 7 | #include 
 8 | #include 
 9 | #include 
10 | #include 
11 | 
12 | const char* NextIdleHarvesterCommandClass::GetName() const
13 | {
14 | 	return "Next Idle Harvester";
15 | }
16 | 
17 | const wchar_t* NextIdleHarvesterCommandClass::GetUIName() const
18 | {
19 | 	return GeneralUtils::LoadStringUnlessMissing("TXT_NEXT_IDLE_HARVESTER", L"Next Idle Harvester");
20 | }
21 | 
22 | const wchar_t* NextIdleHarvesterCommandClass::GetUICategory() const
23 | {
24 | 	return CATEGORY_SELECTION;
25 | }
26 | 
27 | const wchar_t* NextIdleHarvesterCommandClass::GetUIDescription() const
28 | {
29 | 	return GeneralUtils::LoadStringUnlessMissing("TXT_NEXT_IDLE_HARVESTER_DESC", L"Select the next harvester that is idle (not harvesting).");
30 | }
31 | 
32 | void NextIdleHarvesterCommandClass::Execute(WWKey eInput) const
33 | {
34 | 	// Debug::Log("[Phobos] Dummy command runs.\n");
35 | 	// MessageListClass::Instance.PrintMessage(L"[Phobos] Dummy command rums");
36 | 
37 | 	MapClass::Instance.SetTogglePowerMode(0);
38 | 	MapClass::Instance.SetWaypointMode(0, false);
39 | 	MapClass::Instance.SetRepairMode(0);
40 | 	MapClass::Instance.SetSellMode(0);
41 | 
42 | 	auto pObjectToSelect = MapClass::Instance.NextObject(
43 | 		ObjectClass::CurrentObjects.Count ? ObjectClass::CurrentObjects.GetItem(0) : nullptr);
44 | 
45 | 	bool idleHarvestersPresent = false;
46 | 	auto pNextObject = pObjectToSelect;
47 | 
48 | 	do
49 | 	{
50 | 		if (auto pTechno = abstract_cast(pNextObject))
51 | 		{
52 | 			if (auto pTypeExt = TechnoTypeExt::ExtMap.Find(pTechno->GetTechnoType()))
53 | 			{
54 | 				if (pTypeExt->Harvester_Counted && !TechnoExt::IsHarvesting(pTechno))
55 | 				{
56 | 					pObjectToSelect = pNextObject;
57 | 					idleHarvestersPresent = true;
58 | 					break;
59 | 				}
60 | 			}
61 | 		}
62 | 
63 | 		pNextObject = MapClass::Instance.NextObject(pNextObject);
64 | 	}
65 | 	while (pNextObject != pObjectToSelect);
66 | 
67 | 	if (idleHarvestersPresent && pObjectToSelect)
68 | 	{
69 | 		MapClass::UnselectAll();
70 | 		pObjectToSelect->Select();
71 | 		MapClass::Instance.CenterMap();
72 | 		MapClass::Instance.MarkNeedsRedraw(1);
73 | 	}
74 | 	else
75 | 	{
76 | 		MessageListClass::Instance.PrintMessage(StringTable::LoadString("MSG:NothingSelected"), RulesClass::Instance->MessageDelay, HouseClass::CurrentPlayer->ColorSchemeIndex, true);
77 | 	}
78 | }
79 | 


--------------------------------------------------------------------------------
/src/Commands/NextIdleHarvester.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | 
 3 | #include "Commands.h"
 4 | 
 5 | // Select next idle harvester
 6 | class NextIdleHarvesterCommandClass : public CommandClass
 7 | {
 8 | public:
 9 | 	// CommandClass
10 | 	virtual const char* GetName() const override;
11 | 	virtual const wchar_t* GetUIName() const override;
12 | 	virtual const wchar_t* GetUICategory() const override;
13 | 	virtual const wchar_t* GetUIDescription() const override;
14 | 	virtual void Execute(WWKey eInput) const override;
15 | };
16 | 


--------------------------------------------------------------------------------
/src/Commands/ObjectInfo.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | 
 3 | #include "Commands.h"
 4 | 
 5 | // #53 New debug feature for AI scripts
 6 | class ObjectInfoCommandClass : public CommandClass
 7 | {
 8 | public:
 9 | 	// CommandClass
10 | 	virtual const char* GetName() const override;
11 | 	virtual const wchar_t* GetUIName() const override;
12 | 	virtual const wchar_t* GetUICategory() const override;
13 | 	virtual const wchar_t* GetUIDescription() const override;
14 | 	virtual void Execute(WWKey eInput) const override;
15 | };
16 | 


--------------------------------------------------------------------------------
/src/Commands/QuickSave.cpp:
--------------------------------------------------------------------------------
 1 | #include "QuickSave.h"
 2 | 
 3 | #include 
 4 | #include 
 5 | #include 
 6 | #include 
 7 | 
 8 | const char* QuickSaveCommandClass::GetName() const
 9 | {
10 | 	return "Quicksave";
11 | }
12 | 
13 | const wchar_t* QuickSaveCommandClass::GetUIName() const
14 | {
15 | 	return GeneralUtils::LoadStringUnlessMissing("TXT_QUICKSAVE", L"Quicksave");
16 | }
17 | 
18 | const wchar_t* QuickSaveCommandClass::GetUICategory() const
19 | {
20 | 	return CATEGORY_INTERFACE;
21 | }
22 | 
23 | const wchar_t* QuickSaveCommandClass::GetUIDescription() const
24 | {
25 | 	return GeneralUtils::LoadStringUnlessMissing("TXT_QUICKSAVE_DESC", L"Save the current game (Singleplayer only).");
26 | }
27 | 
28 | void QuickSaveCommandClass::Execute(WWKey eInput) const
29 | {
30 | 	auto PrintMessage = [](const wchar_t* pMessage)
31 | 	{
32 | 		MessageListClass::Instance.PrintMessage(
33 | 			pMessage,
34 | 			RulesClass::Instance->MessageDelay,
35 | 			HouseClass::CurrentPlayer->ColorSchemeIndex,
36 | 			true
37 | 		);
38 | 	};
39 | 
40 | 	if (SessionClass::IsSingleplayer())
41 | 	{
42 | 		*reinterpret_cast(0xABCE08) = false;
43 | 		Phobos::ShouldQuickSave = true;
44 | 
45 | 		if (SessionClass::IsCampaign())
46 | 			Phobos::CustomGameSaveDescription = ScenarioClass::Instance->UINameLoaded;
47 | 		else
48 | 			Phobos::CustomGameSaveDescription = ScenarioClass::Instance->Name;
49 | 		Phobos::CustomGameSaveDescription += L" - ";
50 | 		Phobos::CustomGameSaveDescription += GeneralUtils::LoadStringUnlessMissing("TXT_QUICKSAVE_SUFFIX", L"Quicksaved");
51 | 	}
52 | 	else
53 | 	{
54 | 		PrintMessage(GeneralUtils::LoadStringUnlessMissing("MSG:NotAvailableInMultiplayer", L"QuickSave is not available in multiplayer"));
55 | 	}
56 | }
57 | 


--------------------------------------------------------------------------------
/src/Commands/QuickSave.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | 
 3 | #include "Commands.h"
 4 | 
 5 | // Quicksave current game
 6 | class QuickSaveCommandClass : public CommandClass
 7 | {
 8 | public:
 9 | 	// CommandClass
10 | 	virtual const char* GetName() const override;
11 | 	virtual const wchar_t* GetUIName() const override;
12 | 	virtual const wchar_t* GetUICategory() const override;
13 | 	virtual const wchar_t* GetUIDescription() const override;
14 | 	virtual void Execute(WWKey eInput) const override;
15 | };
16 | 


--------------------------------------------------------------------------------
/src/Commands/SaveVariablesToFile.cpp:
--------------------------------------------------------------------------------
 1 | #include "SaveVariablesToFile.h"
 2 | 
 3 | #include 
 4 | #include 
 5 | 
 6 | const char* SaveVariablesToFileCommandClass::GetName() const
 7 | {
 8 | 	return "Save Variables to File";
 9 | }
10 | 
11 | const wchar_t* SaveVariablesToFileCommandClass::GetUIName() const
12 | {
13 | 	return GeneralUtils::LoadStringUnlessMissing("TXT_SAVE_VARIABLES", L"Save Variables to File");
14 | }
15 | 
16 | const wchar_t* SaveVariablesToFileCommandClass::GetUICategory() const
17 | {
18 | 	return CATEGORY_DEVELOPMENT;
19 | }
20 | 
21 | const wchar_t* SaveVariablesToFileCommandClass::GetUIDescription() const
22 | {
23 | 	return GeneralUtils::LoadStringUnlessMissing("TXT_SAVE_VARIABLES_DESC", L"Save local & global variables to an INI file.");
24 | }
25 | 
26 | void SaveVariablesToFileCommandClass::Execute(WWKey eInput) const
27 | {
28 | 	MessageListClass::Instance.PrintMessage(
29 | 		L"Variables saved.",
30 | 		RulesClass::Instance->MessageDelay,
31 | 		HouseClass::CurrentPlayer->ColorSchemeIndex,
32 | 		true
33 | 	);
34 | 
35 | 	ScenarioExt::ExtData::SaveVariablesToFile(false);
36 | 	ScenarioExt::ExtData::SaveVariablesToFile(true);
37 | }
38 | 


--------------------------------------------------------------------------------
/src/Commands/SaveVariablesToFile.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | 
 3 | #include "Commands.h"
 4 | 
 5 | // Display damage strings
 6 | class SaveVariablesToFileCommandClass : public CommandClass
 7 | {
 8 | public:
 9 | 	virtual const char* GetName() const override;
10 | 	virtual const wchar_t* GetUIName() const override;
11 | 	virtual const wchar_t* GetUICategory() const override;
12 | 	virtual const wchar_t* GetUIDescription() const override;
13 | 	virtual void Execute(WWKey eInput) const override;
14 | };
15 | 


--------------------------------------------------------------------------------
/src/Commands/ToggleDesignatorRange.cpp:
--------------------------------------------------------------------------------
 1 | #include "ToggleDesignatorRange.h"
 2 | 
 3 | #include 
 4 | #include 
 5 | 
 6 | const char* ToggleDesignatorRangeCommandClass::GetName() const
 7 | {
 8 | 	return "Toggle Designator Range";
 9 | }
10 | 
11 | const wchar_t* ToggleDesignatorRangeCommandClass::GetUIName() const
12 | {
13 | 	return GeneralUtils::LoadStringUnlessMissing("TXT_DESIGNATOR_RANGE", L"Toggle Designator Range");
14 | }
15 | 
16 | const wchar_t* ToggleDesignatorRangeCommandClass::GetUICategory() const
17 | {
18 | 	return CATEGORY_INTERFACE;
19 | }
20 | 
21 | const wchar_t* ToggleDesignatorRangeCommandClass::GetUIDescription() const
22 | {
23 | 	return GeneralUtils::LoadStringUnlessMissing("TXT_DESIGNATOR_RANGE_DESC", L"Show/hide designator range when targeting superweapons.");
24 | }
25 | 
26 | void ToggleDesignatorRangeCommandClass::Execute(WWKey eInput) const
27 | {
28 | 	Phobos::Config::ShowDesignatorRange = !Phobos::Config::ShowDesignatorRange;
29 | }
30 | 


--------------------------------------------------------------------------------
/src/Commands/ToggleDesignatorRange.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | 
 3 | #include "Commands.h"
 4 | 
 5 | // Display damage strings
 6 | class ToggleDesignatorRangeCommandClass : public CommandClass
 7 | {
 8 | public:
 9 | 	virtual const char* GetName() const override;
10 | 	virtual const wchar_t* GetUIName() const override;
11 | 	virtual const wchar_t* GetUICategory() const override;
12 | 	virtual const wchar_t* GetUIDescription() const override;
13 | 	virtual void Execute(WWKey eInput) const override;
14 | };
15 | 


--------------------------------------------------------------------------------
/src/Commands/ToggleDigitalDisplay.cpp:
--------------------------------------------------------------------------------
 1 | #include "ToggleDigitalDisplay.h"
 2 | 
 3 | #include 
 4 | #include 
 5 | 
 6 | const char* ToggleDigitalDisplayCommandClass::GetName() const
 7 | {
 8 | 	return "Toggle Digital Display";
 9 | }
10 | 
11 | const wchar_t* ToggleDigitalDisplayCommandClass::GetUIName() const
12 | {
13 | 	return GeneralUtils::LoadStringUnlessMissing("TXT_DIGITAL_DISPLAY", L"Toggle Digital Display");
14 | }
15 | 
16 | const wchar_t* ToggleDigitalDisplayCommandClass::GetUICategory() const
17 | {
18 | 	return CATEGORY_INTERFACE;
19 | }
20 | 
21 | const wchar_t* ToggleDigitalDisplayCommandClass::GetUIDescription() const
22 | {
23 | 	return GeneralUtils::LoadStringUnlessMissing("TXT_DIGITAL_DISPLAY_DESC", L"Show/hide digital display of unit data.");
24 | }
25 | 
26 | void ToggleDigitalDisplayCommandClass::Execute(WWKey eInput) const
27 | {
28 | 	Phobos::Config::DigitalDisplay_Enable = !Phobos::Config::DigitalDisplay_Enable;
29 | }
30 | 


--------------------------------------------------------------------------------
/src/Commands/ToggleDigitalDisplay.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | 
 3 | #include "Commands.h"
 4 | 
 5 | // Display damage strings
 6 | class ToggleDigitalDisplayCommandClass : public CommandClass
 7 | {
 8 | public:
 9 | 	virtual const char* GetName() const override;
10 | 	virtual const wchar_t* GetUIName() const override;
11 | 	virtual const wchar_t* GetUICategory() const override;
12 | 	virtual const wchar_t* GetUIDescription() const override;
13 | 	virtual void Execute(WWKey eInput) const override;
14 | };
15 | 


--------------------------------------------------------------------------------
/src/Commands/ToggleSWSidebar.cpp:
--------------------------------------------------------------------------------
 1 | #include "ToggleSWSidebar.h"
 2 | #include 
 3 | 
 4 | #include 
 5 | #include 
 6 | 
 7 | const char* ToggleSWSidebar::GetName() const
 8 | {
 9 | 	return "Toggle Super Weapon Sidebar";
10 | }
11 | 
12 | const wchar_t* ToggleSWSidebar::GetUIName() const
13 | {
14 | 	return GeneralUtils::LoadStringUnlessMissing("TXT_TOGGLE_SW_SIDEBAR", L"Toggle Super Weapon Sidebar");
15 | }
16 | 
17 | const wchar_t* ToggleSWSidebar::GetUICategory() const
18 | {
19 | 	return CATEGORY_INTERFACE;
20 | }
21 | 
22 | const wchar_t* ToggleSWSidebar::GetUIDescription() const
23 | {
24 | 	return GeneralUtils::LoadStringUnlessMissing("TXT_TOGGLE_SW_SIDEBAR_DESC", L"Toggle the Super Weapon Sidebar.");
25 | }
26 | 
27 | void ToggleSWSidebar::Execute(WWKey eInput) const
28 | {
29 | 	ToggleSWButtonClass::SwitchSidebar();
30 | 
31 | 	if (SWSidebarClass::Instance.CurrentColumn)
32 | 		MouseClass::Instance.UpdateCursor(MouseCursorType::Default, false);
33 | }
34 | 


--------------------------------------------------------------------------------
/src/Commands/ToggleSWSidebar.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | 
 3 | #include "Commands.h"
 4 | 
 5 | // Display damage strings
 6 | class ToggleSWSidebar : public CommandClass
 7 | {
 8 | public:
 9 | 	virtual const char* GetName() const override;
10 | 	virtual const wchar_t* GetUIName() const override;
11 | 	virtual const wchar_t* GetUICategory() const override;
12 | 	virtual const wchar_t* GetUIDescription() const override;
13 | 	virtual void Execute(WWKey eInput) const override;
14 | };
15 | 


--------------------------------------------------------------------------------
/src/Ext/Aircraft/Body.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | #include 
 3 | 
 4 | // TODO: Implement proper extended AircraftClass.
 5 | 
 6 | class AircraftExt
 7 | {
 8 | public:
 9 | 	static void FireWeapon(AircraftClass* pThis, AbstractClass* pTarget);
10 | 	static bool PlaceReinforcementAircraft(AircraftClass* pThis, CellStruct edgeCell);
11 | 	static DirType GetLandingDir(AircraftClass* pThis, BuildingClass* pDock = nullptr);
12 | };
13 | 


--------------------------------------------------------------------------------
/src/Ext/Building/Hooks.Refinery.cpp:
--------------------------------------------------------------------------------
 1 | #include "Body.h"
 2 | 
 3 | // The method of calculating the income is subject to each specific situation,
 4 | // which may probably subject to further changes if anyone wants to extend the harvesting logic in the future.
 5 | // I don't want to investigate the details so I check the balance difference directly. --Trsdy
 6 | namespace OwnerBalanceBefore
 7 | {
 8 | 	long HarversterUnloads;
 9 | 	long SlaveComesBack;
10 | }
11 | 
12 | // Unload more than once per ore dump if the harvester contains more than 1 tiberium type
13 | DEFINE_HOOK(0x73E3DB, UnitClass_Mission_Unload_NoteBalanceBefore, 0x6)
14 | {
15 | 	GET(HouseClass* const, pHouse, EBX); // this is the house of the refinery, not the harvester
16 | 	// GET(BuildingClass* const, pDock, EDI);
17 | 	OwnerBalanceBefore::HarversterUnloads = pHouse->Available_Money();// Available_Money takes silos into account
18 | 	return 0;
19 | }
20 | 
21 | DEFINE_HOOK(0x73E4D0, UnitClass_Mission_Unload_CheckBalanceAfter, 0xA)
22 | {
23 | 	GET(HouseClass* const, pHouse, EBX);
24 | 	GET(BuildingClass* const, pDock, EDI);
25 | 
26 | 	if (auto pBldExt = BuildingExt::ExtMap.Find(pDock))
27 | 	{
28 | 		pBldExt->AccumulatedIncome += pHouse->Available_Money() - OwnerBalanceBefore::HarversterUnloads;
29 | 	}
30 | 
31 | 	return 0;
32 | }
33 | 
34 | DEFINE_HOOK(0x522D50, InfantryClass_SlaveGiveMoney_RecordBalanceBefore, 0x5)
35 | {
36 | 	GET_STACK(TechnoClass* const, slaveMiner, 0x4);
37 | 	OwnerBalanceBefore::SlaveComesBack = slaveMiner->Owner->Available_Money();
38 | 	return 0;
39 | }
40 | 
41 | DEFINE_HOOK(0x522E4F, InfantryClass_SlaveGiveMoney_CheckBalanceAfter, 0x6)
42 | {
43 | 	GET_STACK(TechnoClass* const, slaveMiner, STACK_OFFSET(0x18, 0x4));
44 | 
45 | 	int money = slaveMiner->Owner->Available_Money() - OwnerBalanceBefore::SlaveComesBack;
46 | 
47 | 	if (auto pBld = abstract_cast(slaveMiner))
48 | 	{
49 | 		auto pBldExt = BuildingExt::ExtMap.Find(pBld);
50 | 		pBldExt->AccumulatedIncome += money;
51 | 	}
52 | 	else if (auto pBldTypeExt = BuildingTypeExt::ExtMap.Find(slaveMiner->GetTechnoType()->DeploysInto))
53 | 	{
54 | 		if (pBldTypeExt->DisplayIncome.Get(RulesExt::Global()->DisplayIncome.Get()))
55 | 			FlyingStrings::AddMoneyString(money, slaveMiner->Owner, RulesExt::Global()->DisplayIncome_Houses.Get(), slaveMiner->Location);
56 | 	}
57 | 
58 | 	return 0;
59 | }
60 | 


--------------------------------------------------------------------------------
/src/Ext/Bullet/Trajectories/SampleTrajectory.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | 
 3 | #include "PhobosTrajectory.h"
 4 | 
 5 | class SampleTrajectoryType final : public PhobosTrajectoryType
 6 | {
 7 | public:
 8 | 	SampleTrajectoryType() : PhobosTrajectoryType()
 9 | 		, TargetSnapDistance { Leptons(128) }
10 | 	{ }
11 | 
12 | 	virtual bool Load(PhobosStreamReader& Stm, bool RegisterForChange) override;
13 | 	virtual bool Save(PhobosStreamWriter& Stm) const override;
14 | 	virtual std::unique_ptr CreateInstance() const override;
15 | 	virtual TrajectoryFlag Flag() const override { return TrajectoryFlag::Invalid; } // TrajectoryFlag
16 | 	virtual void Read(CCINIClass* const pINI, const char* pSection) override;
17 | 
18 | 	Valueable TargetSnapDistance;
19 | 
20 | private:
21 | 	template 
22 | 	void Serialize(T& Stm);
23 | };
24 | 
25 | class SampleTrajectory final : public PhobosTrajectory
26 | {
27 | public:
28 | 	SampleTrajectory(noinit_t) { }
29 | 
30 | 	SampleTrajectory(SampleTrajectoryType const* trajType) : Type { trajType }
31 | 		, TargetSnapDistance { trajType->TargetSnapDistance }
32 | 	{ }
33 | 
34 | 	virtual bool Load(PhobosStreamReader& Stm, bool RegisterForChange) override;
35 | 	virtual bool Save(PhobosStreamWriter& Stm) const override;
36 | 	virtual TrajectoryFlag Flag() const override { return TrajectoryFlag::Invalid; } // TrajectoryFlag
37 | 	virtual void OnUnlimbo(BulletClass* pBullet, CoordStruct* pCoord, BulletVelocity* pVelocity) override;
38 | 	virtual bool OnAI(BulletClass* pBullet) override;
39 | 	virtual void OnAIPreDetonate(BulletClass* pBullet) override;
40 | 	virtual void OnAIVelocity(BulletClass* pBullet, BulletVelocity* pSpeed, BulletVelocity* pPosition) override;
41 | 	virtual TrajectoryCheckReturnType OnAITargetCoordCheck(BulletClass* pBullet) override;
42 | 	virtual TrajectoryCheckReturnType OnAITechnoCheck(BulletClass* pBullet, TechnoClass* pTechno) override;
43 | 
44 | 	SampleTrajectoryType const* Type;
45 | 	Leptons TargetSnapDistance;
46 | 
47 | private:
48 | 	template 
49 | 	void Serialize(T& Stm);
50 | };
51 | 


--------------------------------------------------------------------------------
/src/Ext/CaptureManager/Body.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | 
 3 | #include 
 4 | #include 
 5 | #include 
 6 | #include 
 7 | #include 
 8 | #include 
 9 | 
10 | #include 
11 | 
12 | class CaptureManagerExt
13 | {
14 | public:
15 | 	static bool CanCapture(CaptureManagerClass* pManager, TechnoClass* pTarget);
16 | 	static bool FreeUnit(CaptureManagerClass* pManager, TechnoClass* pTarget, bool silent = false);
17 | 	static bool CaptureUnit(CaptureManagerClass* pManager, TechnoClass* pTarget, bool bRemoveFirst,
18 | 		AnimTypeClass* pControlledAnimType = RulesClass::Instance->ControlledAnimationType, bool silent = false, int threatDelay = 0);
19 | 	static bool CaptureUnit(CaptureManagerClass* pManager, AbstractClass* pTechno,
20 | 		AnimTypeClass* pControlledAnimType = RulesClass::Instance->ControlledAnimationType, int threatDelay = 0);
21 | 	static void DecideUnitFate(CaptureManagerClass* pManager, FootClass* pFoot);
22 | };
23 | 


--------------------------------------------------------------------------------
/src/Ext/Cell/Body.cpp:
--------------------------------------------------------------------------------
  1 | #include "Body.h"
  2 | 
  3 | #include 
  4 | 
  5 | #include 
  6 | 
  7 | CellExt::ExtContainer CellExt::ExtMap;
  8 | 
  9 | // =============================
 10 | // load / save
 11 | 
 12 | template 
 13 | void CellExt::ExtData::Serialize(T& Stm)
 14 | {
 15 | 	Stm
 16 | 		.Process(this->RadSites)
 17 | 		.Process(this->RadLevels)
 18 | 		;
 19 | }
 20 | 
 21 | void CellExt::ExtData::LoadFromStream(PhobosStreamReader& Stm)
 22 | {
 23 | 	Extension::LoadFromStream(Stm);
 24 | 	this->Serialize(Stm);
 25 | }
 26 | 
 27 | void CellExt::ExtData::SaveToStream(PhobosStreamWriter& Stm)
 28 | {
 29 | 	Extension::SaveToStream(Stm);
 30 | 	this->Serialize(Stm);
 31 | }
 32 | 
 33 | void CellExt::ExtData::InvalidatePointer(void* ptr, bool removed)
 34 | { }
 35 | 
 36 | bool CellExt::RadLevel::Load(PhobosStreamReader& stm, bool registerForChange)
 37 | {
 38 | 	return this->Serialize(stm);
 39 | }
 40 | 
 41 | bool CellExt::RadLevel::Save(PhobosStreamWriter& stm) const
 42 | {
 43 | 	return const_cast(this)->Serialize(stm);
 44 | }
 45 | 
 46 | template 
 47 | bool CellExt::RadLevel::Serialize(T& stm)
 48 | {
 49 | 	return stm
 50 | 		.Process(this->Rad)
 51 | 		.Process(this->Level)
 52 | 		.Success();
 53 | }
 54 | 
 55 | // =============================
 56 | // container
 57 | 
 58 | CellExt::ExtContainer::ExtContainer() : Container("CellClass") { }
 59 | CellExt::ExtContainer::~ExtContainer() = default;
 60 | 
 61 | bool CellExt::ExtContainer::InvalidateExtDataIgnorable(void* const ptr) const
 62 | {
 63 | 	return true;
 64 | }
 65 | 
 66 | // =============================
 67 | // container hooks
 68 | 
 69 | DEFINE_HOOK(0x47BDA1, CellClass_CTOR, 0x5)
 70 | {
 71 | 	GET(CellClass*, pItem, ESI);
 72 | 
 73 | 	CellExt::ExtMap.Allocate(pItem);
 74 | 
 75 | 	return 0;
 76 | }
 77 | 
 78 | DEFINE_HOOK(0x47BB60, CellClass_DTOR, 0x6)
 79 | {
 80 | 	GET(CellClass*, pItem, ECX);
 81 | 
 82 | 	CellExt::ExtMap.Remove(pItem);
 83 | 
 84 | 	return 0;
 85 | }
 86 | 
 87 | DEFINE_HOOK_AGAIN(0x483C10, CellClass_SaveLoad_Prefix, 0x5)
 88 | DEFINE_HOOK(0x4839F0, CellClass_SaveLoad_Prefix, 0x7)
 89 | {
 90 | 	GET_STACK(CellClass*, pItem, 0x4);
 91 | 	GET_STACK(IStream*, pStm, 0x8);
 92 | 
 93 | 	CellExt::ExtMap.PrepareStream(pItem, pStm);
 94 | 
 95 | 	return 0;
 96 | }
 97 | 
 98 | DEFINE_HOOK(0x483C00, CellClass_Load_Suffix, 5)
 99 | {
100 | 	CellExt::ExtMap.LoadStatic();
101 | 	return 0;
102 | }
103 | 
104 | DEFINE_HOOK(0x483C79, CellClass_Save_Suffix, 0x6)
105 | {
106 | 	CellExt::ExtMap.SaveStatic();
107 | 	return 0;
108 | }
109 | 


--------------------------------------------------------------------------------
/src/Ext/Cell/Body.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | #include 
 3 | 
 4 | #include 
 5 | #include 
 6 | #include 
 7 | 
 8 | class CellExt
 9 | {
10 | public:
11 | 	using base_type = CellClass;
12 | 
13 | 	static constexpr DWORD Canary = 0x13371337;
14 | 	static constexpr size_t ExtPointerOffset = 0x144;
15 | 
16 | 	struct RadLevel
17 | 	{
18 | 		RadSiteClass* Rad { nullptr };
19 | 		int Level { 0 };
20 | 
21 | 		RadLevel() = default;
22 | 		RadLevel(RadSiteClass* pRad, int level) : Rad(pRad), Level(level)
23 | 		{ }
24 | 
25 | 		bool Load(PhobosStreamReader& stm, bool registerForChange);
26 | 		bool Save(PhobosStreamWriter& stm) const;
27 | 
28 | 	private:
29 | 		template 
30 | 		bool Serialize(T& stm);
31 | 	};
32 | 
33 | 	class ExtData final : public Extension
34 | 	{
35 | 	public:
36 | 		std::vector RadSites {};
37 | 		std::vector RadLevels { };
38 | 
39 | 		ExtData(CellClass* OwnerObject) : Extension(OwnerObject)
40 | 		{ }
41 | 
42 | 		virtual ~ExtData() = default;
43 | 
44 | 		virtual void InvalidatePointer(void* ptr, bool removed) override;
45 | 
46 | 		virtual void LoadFromStream(PhobosStreamReader& Stm) override;
47 | 		virtual void SaveToStream(PhobosStreamWriter& Stm) override;
48 | 
49 | 	private:
50 | 		template 
51 | 		void Serialize(T& Stm);
52 | 	};
53 | 
54 | 	class ExtContainer final : public Container
55 | 	{
56 | 	public:
57 | 		ExtContainer();
58 | 		~ExtContainer();
59 | 
60 | 		virtual bool InvalidateExtDataIgnorable(void* const ptr) const override;
61 | 	};
62 | 
63 | 	static ExtContainer ExtMap;
64 | };
65 | 


--------------------------------------------------------------------------------
/src/Ext/Event/Body.cpp:
--------------------------------------------------------------------------------
  1 | /*
  2 | #include "Body.h"
  3 | 
  4 | #include 
  5 | #include 
  6 | 
  7 | bool EventExt::AddEvent()
  8 | {
  9 | 	return EventClass::AddEvent(*reinterpret_cast(this));
 10 | }
 11 | 
 12 | void EventExt::RespondEvent()
 13 | {
 14 | 	switch (this->Type)
 15 | 	{
 16 | 	case EventTypeExt::Sample:
 17 | 		// Place the handler here
 18 | 		break;
 19 | 	}
 20 | }
 21 | 
 22 | size_t EventExt::GetDataSize(EventTypeExt type)
 23 | {
 24 | 	switch (type)
 25 | 	{
 26 | 	case EventTypeExt::Sample:
 27 | 		return sizeof(EventExt::Sample);
 28 | 	}
 29 | 
 30 | 	return 0;
 31 | }
 32 | 
 33 | bool EventExt::IsValidType(EventTypeExt type)
 34 | {
 35 | 	return (type >= EventTypeExt::FIRST && type <= EventTypeExt::LAST);
 36 | }
 37 | 
 38 | // hooks
 39 | 
 40 | DEFINE_HOOK(0x4C6CC8, Networking_RespondToEvent, 0x5)
 41 | {
 42 | 	GET(EventExt*, pEvent, ESI);
 43 | 
 44 | 	if (EventExt::IsValidType(pEvent->Type))
 45 | 	{
 46 | 		pEvent->RespondEvent();
 47 | 	}
 48 | 
 49 | 	return 0;
 50 | }
 51 | 
 52 | DEFINE_HOOK(0x64B6FE, sub_64B660_GetEventSize, 0x6)
 53 | {
 54 | 	const auto eventType = static_cast(R->EDI() & 0xFF);
 55 | 
 56 | 	if (EventExt::IsValidType(eventType))
 57 | 	{
 58 | 		const size_t eventSize = EventExt::GetDataSize(eventType);
 59 | 
 60 | 		R->EDX(eventSize);
 61 | 		R->EBP(eventSize);
 62 | 		return 0x64B71D;
 63 | 	}
 64 | 
 65 | 	return 0;
 66 | }
 67 | 
 68 | DEFINE_HOOK(0x64BE7D, sub_64BDD0_GetEventSize1, 0x6)
 69 | {
 70 | 	const auto eventType = static_cast(R->EDI() & 0xFF);
 71 | 
 72 | 	if (EventExt::IsValidType(eventType))
 73 | 	{
 74 | 		const size_t eventSize = EventExt::GetDataSize(eventType);
 75 | 
 76 | 		REF_STACK(size_t, eventSizeInStack, STACK_OFFSET(0xAC, -0x8C));
 77 | 		eventSizeInStack = eventSize;
 78 | 		R->ECX(eventSize);
 79 | 		R->EBP(eventSize);
 80 | 		return 0x64BE97;
 81 | 	}
 82 | 
 83 | 	return 0;
 84 | }
 85 | 
 86 | DEFINE_HOOK(0x64C30E, sub_64BDD0_GetEventSize2, 0x6)
 87 | {
 88 | 	const auto eventType = static_cast(R->ESI() & 0xFF);
 89 | 
 90 | 	if (EventExt::IsValidType(eventType))
 91 | 	{
 92 | 		const size_t eventSize = EventExt::GetDataSize(eventType);
 93 | 
 94 | 		R->ECX(eventSize);
 95 | 		R->EBP(eventSize);
 96 | 		return 0x64C321;
 97 | 	}
 98 | 
 99 | 	return 0;
100 | }
101 | */
102 | 


--------------------------------------------------------------------------------
/src/Ext/Event/Body.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | /*
 3 | #include 
 4 | #include 
 5 | 
 6 | enum class EventTypeExt : uint8_t
 7 | {
 8 | 	// Vanilla game used Events from 0x00 to 0x2F
 9 | 	// CnCNet reserved Events from 0x30 to 0x3F
10 | 	// Ares used Events 0x60 and 0x61
11 | 
12 | 	Sample = 0x40, // Sample event, remove it when Phobos needs its own events
13 | 
14 | 	FIRST = Sample,
15 | 	LAST = Sample
16 | };
17 | 
18 | #pragma pack(push, 1)
19 | class EventExt
20 | {
21 | public:
22 | 	EventTypeExt Type;
23 | 	bool IsExecuted;
24 | 	char HouseIndex;
25 | 	uint32_t Frame;
26 | 	union
27 | 	{
28 | 		char DataBuffer[104];
29 | 
30 | 		struct Sample
31 | 		{
32 | 			char DataBuffer[104];
33 | 		} Sample;
34 | 	};
35 | 
36 | 	bool AddEvent();
37 | 	void RespondEvent();
38 | 
39 | 	static size_t GetDataSize(EventTypeExt type);
40 | 	static bool IsValidType(EventTypeExt type);
41 | };
42 | 
43 | static_assert(sizeof(EventExt) == 111);
44 | static_assert(offsetof(EventExt, DataBuffer) == 7);
45 | #pragma pack(pop)
46 | */
47 | 


--------------------------------------------------------------------------------
/src/Ext/House/Hooks.ForceEnemy.cpp:
--------------------------------------------------------------------------------
 1 | #include "Body.h"
 2 | 
 3 | DEFINE_HOOK(0x5047D0, HouseClass_UpdateAngerNodes_SetForceEnemy, 0x6)
 4 | {
 5 | 	GET(HouseClass*, pThis, EAX);
 6 | 	enum { ReturnValue = 0x50483F };
 7 | 
 8 | 	if (pThis)
 9 | 	{
10 | 		int forceIndex = HouseExt::ExtMap.Find(pThis)->GetForceEnemyIndex();
11 | 
12 | 		if (forceIndex >= 0 || forceIndex == -2)
13 | 		{
14 | 			R->EDX(forceIndex == -2 ? -1 : forceIndex);
15 | 			return ReturnValue;
16 | 		}
17 | 	}
18 | 
19 | 	return 0;
20 | }
21 | 
22 | DEFINE_HOOK_AGAIN(0x4F9BFC, HouseClass_ClearForceEnemy, 0xA)	// HouseClass_MakeAlly
23 | DEFINE_HOOK(0x4FD772, HouseClass_ClearForceEnemy, 0xA)			// HouseClass_UpdateAI
24 | {
25 | 	HouseClass* pThis = nullptr;
26 | 
27 | 	if (R->Origin() == 0x4FD772)
28 | 		pThis = R->EBX();
29 | 	else
30 | 		pThis = R->ESI();
31 | 
32 | 	if (pThis)
33 | 	{
34 | 		HouseExt::ExtMap.Find(pThis)->SetForceEnemyIndex(-1);
35 | 		pThis->UpdateAngerNodes(0, pThis);
36 | 		return R->Origin() + 0xA;
37 | 	}
38 | 
39 | 	return 0;
40 | }
41 | 


--------------------------------------------------------------------------------
/src/Ext/House/Hooks.UnitFromFactory.cpp:
--------------------------------------------------------------------------------
 1 | #include 
 2 | 
 3 | #include 
 4 | #include 
 5 | #include 
 6 | #include 
 7 | 
 8 | DEFINE_HOOK(0x4FB63A, HouseClass_UnitFromFactory_DisablingEVAUnitReady, 0xF)
 9 | {
10 | 	if (!RulesExt::Global()->IsVoiceCreatedGlobal.Get())
11 | 		VoxClass::Play(GameStrings::EVA_UnitReady);
12 | 
13 | 	return 0x4FB649;
14 | }
15 | 
16 | DEFINE_HOOK(0x4FB64B, HouseClass_UnitFromFactory_VoiceCreated, 0x5)
17 | {
18 | 	GET(TechnoClass* const, pThisTechno, ESI);
19 | 	GET(FactoryClass* const, pThisFactory, EBX);
20 | 
21 | 	auto const pThisTechnoType = TechnoTypeExt::ExtMap.Find(pThisTechno->GetTechnoType());
22 | 	if (pThisTechno->Owner->IsControlledByCurrentPlayer() && pThisTechnoType->VoiceCreated.isset())
23 | 	{
24 | 		if (RulesExt::Global()->IsVoiceCreatedGlobal.Get())
25 | 			pThisTechno->QueueVoice(pThisTechnoType->VoiceCreated);
26 | 		else
27 | 			VocClass::PlayAt(pThisTechnoType->VoiceCreated, pThisTechno->Location);
28 | 	}
29 | 
30 | 	pThisFactory->CompletedProduction();
31 | 	return 0x4FB650;
32 | }
33 | 


--------------------------------------------------------------------------------
/src/Ext/OverlayType/Body.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | #include 
 3 | 
 4 | #include 
 5 | #include 
 6 | #include 
 7 | #include 
 8 | 
 9 | class OverlayTypeExt
10 | {
11 | public:
12 | 	using base_type = OverlayTypeClass;
13 | 
14 | 	static constexpr DWORD Canary = 0xADF48498;
15 | 	static constexpr size_t ExtPointerOffset = 0x18;
16 | 
17 | 	class ExtData final : public Extension
18 | 	{
19 | 	public:
20 | 		Valueable ZAdjust;
21 | 		PhobosFixedString<32u> PaletteFile;
22 | 		DynamicVectorClass* Palette; // Intentionally not serialized - rebuilt from the palette file on load.
23 | 
24 | 		ExtData(OverlayTypeClass* OwnerObject) : Extension(OwnerObject)
25 | 			, ZAdjust { 0 }
26 | 			, PaletteFile {}
27 | 			, Palette {}
28 | 		{ }
29 | 
30 | 		virtual ~ExtData() = default;
31 | 
32 | 		virtual void LoadFromINIFile(CCINIClass* pINI) override;
33 | 
34 | 		virtual void InvalidatePointer(void* ptr, bool bRemoved) override { }
35 | 
36 | 		virtual void LoadFromStream(PhobosStreamReader& Stm) override;
37 | 		virtual void SaveToStream(PhobosStreamWriter& Stm) override;
38 | 
39 | 	private:
40 | 		template 
41 | 		void Serialize(T& Stm);
42 | 	};
43 | 
44 | 	class ExtContainer final : public Container
45 | 	{
46 | 	public:
47 | 		ExtContainer();
48 | 		~ExtContainer();
49 | 	};
50 | 
51 | 	static ExtContainer ExtMap;
52 | 
53 | 	static bool LoadGlobals(PhobosStreamReader& Stm);
54 | 	static bool SaveGlobals(PhobosStreamWriter& Stm);
55 | };
56 | 


--------------------------------------------------------------------------------
/src/Ext/OverlayType/Hooks.cpp:
--------------------------------------------------------------------------------
 1 | #include "Body.h"
 2 | 
 3 | #include 
 4 | 
 5 | DEFINE_HOOK(0x47F71D, CellClass_DrawOverlay_ZAdjust, 0x5)
 6 | {
 7 | 	GET(int, zAdjust, EDI);
 8 | 	GET_STACK(OverlayTypeClass*, pOverlayType, STACK_OFFSET(0x24, -0x14));
 9 | 
10 | 	auto const pTypeExt = OverlayTypeExt::ExtMap.Find(pOverlayType);
11 | 
12 | 	if (pTypeExt->ZAdjust != 0)
13 | 		R->EDI(zAdjust - pTypeExt->ZAdjust);
14 | 
15 | 	return 0;
16 | }
17 | 
18 | // Replaces an Ares hook at 0x47F9A4
19 | DEFINE_HOOK(0x47F974, CellClass_DrawOverlay_Walls, 0x5)
20 | {
21 | 	enum { SkipGameCode = 0x47FB86 };
22 | 
23 | 	GET(CellClass*, pThis, ESI);
24 | 	GET(SHPStruct*, pShape, EAX);
25 | 	GET(RectangleStruct*, pBounds, EBP);
26 | 	GET(int, zAdjust, EDI);
27 | 	GET_STACK(OverlayTypeClass*, pOverlayType, STACK_OFFSET(0x24, -0x14));
28 | 	REF_STACK(Point2D, pLocation, STACK_OFFSET(0x24, -0x10));
29 | 
30 | 	int wallOwnerIndex = pThis->WallOwnerIndex;
31 | 	int colorSchemeIndex = HouseClass::CurrentPlayer->ColorSchemeIndex;
32 | 
33 | 	if (wallOwnerIndex >= 0)
34 | 		colorSchemeIndex = HouseClass::Array[wallOwnerIndex]->ColorSchemeIndex;
35 | 
36 | 	LightConvertClass* pConvert = nullptr;
37 | 	auto const pTypeExt = OverlayTypeExt::ExtMap.Find(pOverlayType);
38 | 
39 | 	if (pTypeExt->Palette)
40 | 		pConvert = pTypeExt->Palette->Items[colorSchemeIndex]->LightConvert;
41 | 	else
42 | 		pConvert = ColorScheme::Array[colorSchemeIndex]->LightConvert;
43 | 
44 | 	DSurface::Temp->DrawSHP(pConvert, pShape, pThis->OverlayData, &pLocation, pBounds,
45 | 		BlitterFlags(0x4E00), 0, -2 - zAdjust, ZGradient::Deg90, pThis->Intensity_Normal, 0, 0, 0, 0, 0);
46 | 
47 | 	return SkipGameCode;
48 | }
49 | 


--------------------------------------------------------------------------------
/src/Ext/ParticleSystemType/Body.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | #include 
 3 | 
 4 | #include 
 5 | #include 
 6 | #include 
 7 | #include 
 8 | #include 
 9 | 
10 | class ParticleSystemTypeExt
11 | {
12 | public:
13 | 	using base_type = ParticleSystemTypeClass;
14 | 
15 | 	static constexpr DWORD Canary = 0xF9984EFE;
16 | 	static constexpr size_t ExtPointerOffset = 0x18;
17 | 
18 | 	class ExtData final : public Extension
19 | 	{
20 | 	public:
21 | 		Valueable AdjustTargetCoordsOnRotation;
22 | 
23 | 		ExtData(ParticleSystemTypeClass* OwnerObject) : Extension(OwnerObject)
24 | 			, AdjustTargetCoordsOnRotation { true }
25 | 		{ }
26 | 
27 | 		virtual ~ExtData() = default;
28 | 
29 | 		virtual void LoadFromINIFile(CCINIClass* pINI) override;
30 | 
31 | 		virtual void InvalidatePointer(void* ptr, bool bRemoved) override { }
32 | 
33 | 		virtual void LoadFromStream(PhobosStreamReader& Stm) override;
34 | 		virtual void SaveToStream(PhobosStreamWriter& Stm) override;
35 | 
36 | 	private:
37 | 		template 
38 | 		void Serialize(T& Stm);
39 | 	};
40 | 
41 | 	class ExtContainer final : public Container
42 | 	{
43 | 	public:
44 | 		ExtContainer();
45 | 		~ExtContainer();
46 | 	};
47 | 
48 | 	static ExtContainer ExtMap;
49 | 
50 | 	static bool LoadGlobals(PhobosStreamReader& Stm);
51 | 	static bool SaveGlobals(PhobosStreamWriter& Stm);
52 | };
53 | 


--------------------------------------------------------------------------------
/src/Ext/ParticleType/Body.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | 
 3 | #include 
 4 | 
 5 | #include 
 6 | #include 
 7 | #include 
 8 | #include 
 9 | 
10 | class ParticleTypeExt
11 | {
12 | public:
13 | 	using base_type = ParticleTypeClass;
14 | 
15 | 	static constexpr DWORD Canary = 0xEAFEEAFE;
16 | 	static constexpr size_t ExtPointerOffset = 0x18;
17 | 
18 | 	class ExtData final : public Extension
19 | 	{
20 | 	public:
21 | 		Valueable Gas_MaxDriftSpeed;
22 | 
23 | 		ExtData(ParticleTypeClass* OwnerObject) : Extension(OwnerObject)
24 | 			, Gas_MaxDriftSpeed { 2 }
25 | 		{ }
26 | 
27 | 		virtual ~ExtData() = default;
28 | 
29 | 		virtual void LoadFromINIFile(CCINIClass* pINI) override;
30 | 
31 | 		virtual void InvalidatePointer(void* ptr, bool bRemoved) override { }
32 | 
33 | 		virtual void LoadFromStream(PhobosStreamReader& Stm) override;
34 | 		virtual void SaveToStream(PhobosStreamWriter& Stm) override;
35 | 
36 | 	private:
37 | 		template 
38 | 		void Serialize(T& Stm);
39 | 	};
40 | 
41 | 	class ExtContainer final : public Container
42 | 	{
43 | 	public:
44 | 		ExtContainer();
45 | 		~ExtContainer();
46 | 	};
47 | 
48 | 	static ExtContainer ExtMap;
49 | 
50 | 	static bool LoadGlobals(PhobosStreamReader& Stm);
51 | 	static bool SaveGlobals(PhobosStreamWriter& Stm);
52 | };
53 | 


--------------------------------------------------------------------------------
/src/Ext/ParticleType/Hooks.cpp:
--------------------------------------------------------------------------------
 1 | #include "Body.h"
 2 | 
 3 | #include 
 4 | 
 5 | DEFINE_HOOK(0x62BE30, ParticleClass_Gas_AI_DriftSpeed, 0x5)
 6 | {
 7 | 	enum { ContinueAI = 0x62BE60 };
 8 | 
 9 | 	GET(ParticleClass*, pParticle, EBP);
10 | 
11 | 	auto pExt = ParticleTypeExt::ExtMap.Find(pParticle->Type);
12 | 	int maxDriftSpeed = pExt->Gas_MaxDriftSpeed;
13 | 	int minDriftSpeed = -maxDriftSpeed;
14 | 
15 | 	if (pParticle->Velocity.X > maxDriftSpeed)
16 | 		pParticle->Velocity.X = maxDriftSpeed;
17 | 	else if (pParticle->Velocity.X < minDriftSpeed)
18 | 		pParticle->Velocity.X = minDriftSpeed;
19 | 
20 | 	if (pParticle->Velocity.Y > maxDriftSpeed)
21 | 		pParticle->Velocity.Y = maxDriftSpeed;
22 | 	else if (pParticle->Velocity.Y < minDriftSpeed)
23 | 		pParticle->Velocity.Y = minDriftSpeed;
24 | 
25 | 	return ContinueAI;
26 | }
27 | 


--------------------------------------------------------------------------------
/src/Ext/RadSite/Body.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | 
 3 | #include 
 4 | 
 5 | #include 
 6 | #include 
 7 | #include 
 8 | 
 9 | #include 
10 | 
11 | class RadTypeClass;
12 | 
13 | class RadSiteExt
14 | {
15 | public:
16 | 	using base_type = RadSiteClass;
17 | 
18 | 	static constexpr DWORD Canary = 0x88446622;
19 | 	static constexpr size_t ExtPointerOffset = 0x18;
20 | 	static constexpr bool ShouldConsiderInvalidatePointer = true;
21 | 
22 | 	class ExtData final : public Extension
23 | 	{
24 | 	public:
25 | 		WeaponTypeClass* Weapon;
26 | 		RadTypeClass* Type;
27 | 		HouseClass* RadHouse;
28 | 		TechnoClass* RadInvoker;
29 | 
30 | 		ExtData(RadSiteClass* OwnerObject) : Extension(OwnerObject)
31 | 			, RadHouse { nullptr }
32 | 			, RadInvoker { nullptr }
33 | 			, Type {}
34 | 			, Weapon { nullptr }
35 | 		{ }
36 | 
37 | 		virtual ~ExtData() = default;
38 | 
39 | 		bool ApplyRadiationDamage(TechnoClass* pTarget, int& damage);
40 | 		void Add(int amount);
41 | 		void SetRadLevel(int amount);
42 | 		// double GetRadLevelAt(CellStruct const& cell) const;
43 | 		void CreateLight();
44 | 
45 | 		virtual void LoadFromStream(PhobosStreamReader& Stm) override;
46 | 		virtual void SaveToStream(PhobosStreamWriter& Stm) override;
47 | 		virtual void Initialize() override;
48 | 
49 | 		virtual void InvalidatePointer(void* ptr, bool bRemoved) override
50 | 		{
51 | 			AnnounceInvalidPointer(RadInvoker, ptr);
52 | 		}
53 | 
54 | 	private:
55 | 		template 
56 | 		void Serialize(T& Stm);
57 | 	};
58 | 
59 | 	static void CreateInstance(CellStruct location, int spread, int radLevel, WeaponTypeExt::ExtData* pWeaponExt, HouseClass* const pOwner, TechnoClass* const pInvoker);
60 | 
61 | 	class ExtContainer final : public Container
62 | 	{
63 | 	public:
64 | 		ExtContainer();
65 | 		~ExtContainer();
66 | 
67 | 		virtual bool InvalidateExtDataIgnorable(void* const ptr) const override
68 | 		{
69 | 			auto const abs = static_cast(ptr)->WhatAmI();
70 | 			switch (abs)
71 | 			{
72 | 			case AbstractType::Aircraft:
73 | 			case AbstractType::Building:
74 | 			case AbstractType::Infantry:
75 | 			case AbstractType::Unit:
76 | 				return false;
77 | 			default:
78 | 				return true;
79 | 			}
80 | 		}
81 | 	};
82 | 
83 | 	static ExtContainer ExtMap;
84 | };
85 | 


--------------------------------------------------------------------------------
/src/Ext/SWType/NewSWType/NewSWType.cpp:
--------------------------------------------------------------------------------
 1 | #include "NewSWType.h"
 2 | 
 3 | std::vector> NewSWType::Array;
 4 | 
 5 | void NewSWType::Register(std::unique_ptr pType)
 6 | {
 7 | 	//Ares capture positive, so we use negative...
 8 | 	pType->SetTypeIndex(-static_cast(Array.size() + 2));
 9 | 	Array.emplace_back(std::move(pType));
10 | }
11 | 
12 | void NewSWType::Init()
13 | {
14 | 	if (!Array.empty())
15 | 		return;
16 | }
17 | 
18 | void NewSWType::Clear()
19 | {
20 | 	Array.clear();
21 | }
22 | 
23 | int NewSWType::GetNewSWTypeIdx(const char* TypeID)
24 | {
25 | 	for (const auto& pNewSWType : Array)
26 | 	{
27 | 		if (!_strcmpi(pNewSWType->GetTypeID(), TypeID))
28 | 			return pNewSWType->GetTypeIndex();
29 | 	}
30 | 
31 | 	return -1;
32 | }
33 | 
34 | NewSWType* NewSWType::GetNthItem(int idx)
35 | {
36 | 	return Array[-idx - 2].get();
37 | }
38 | 
39 | int NewSWType::GetTypeIndex()
40 | {
41 | 	return this->TypeIndex;
42 | }
43 | 
44 | void NewSWType::SetTypeIndex(int idx)
45 | {
46 | 	this->TypeIndex = idx;
47 | }
48 | 
49 | bool NewSWType::LoadGlobals(PhobosStreamReader& stm)
50 | {
51 | 	Init();
52 | 
53 | 	for (const auto& pNewSWType : Array)
54 | 	{
55 | 		stm.RegisterChange(pNewSWType.get());
56 | 	}
57 | 
58 | 	return stm.Success();
59 | }
60 | 
61 | bool NewSWType::SaveGlobals(PhobosStreamWriter& stm)
62 | {
63 | 	for (const auto& pNewSWType : Array)
64 | 	{
65 | 		stm.Save(pNewSWType.get());
66 | 	}
67 | 
68 | 	return stm.Success();
69 | }
70 | 


--------------------------------------------------------------------------------
/src/Ext/SWType/NewSWType/NewSWType.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | #include 
 3 | #include 
 4 | #include 
 5 | 
 6 | class NewSWType
 7 | {
 8 | public:
 9 | 
10 | 	static void Init();
11 | 	static void Clear();
12 | 	static int GetNewSWTypeIdx(const char* TypeID);
13 | 	static NewSWType* GetNthItem(int idx);
14 | 
15 | 	virtual ~NewSWType() = default;
16 | 
17 | 	virtual int GetTypeIndex() final;
18 | 
19 | 	// selectable override
20 | 
21 | 	virtual void Initialize(SWTypeExt::ExtData* pData, SuperWeaponTypeClass* pSW) { }
22 | 	virtual void LoadFromINI(SWTypeExt::ExtData* pData, SuperWeaponTypeClass* pSW, CCINIClass* pINI) { }
23 | 
24 | 	// must be override
25 | 
26 | 	virtual const char* GetTypeID() = 0;
27 | 	virtual bool Activate(SuperClass* pSW, const CellStruct& cell, bool isPlayer) = 0;
28 | 
29 | 	static bool LoadGlobals(PhobosStreamReader& stm);
30 | 	static bool SaveGlobals(PhobosStreamWriter& stm);
31 | 
32 | protected:
33 | 	virtual void SetTypeIndex(int idx) final;
34 | 
35 | private:
36 | 	static std::vector> Array;
37 | 	static void Register(std::unique_ptr pType);
38 | 
39 | 	int TypeIndex = -1;
40 | };
41 | 


--------------------------------------------------------------------------------
/src/Ext/Side/Hooks.SidebarGDIPositions.cpp:
--------------------------------------------------------------------------------
 1 | #include 
 2 | #include "Body.h"
 3 | 
 4 | bool isNODSidebar = false;
 5 | 
 6 | DEFINE_HOOK(0x534FA7, Prep_For_Side, 0x5)
 7 | {
 8 | 	GET(int, sideIndex, ECX);
 9 | 	auto pSide = SideClass::Array.GetItem(sideIndex);
10 | 	auto pSideExt = pSide ? SideExt::ExtMap.Find(pSide) : nullptr;
11 | 	isNODSidebar = pSideExt ? !pSideExt->Sidebar_GDIPositions : sideIndex;
12 | 
13 | 	return 0;
14 | }
15 | 
16 | DEFINE_HOOK(0x652EAB, RadarClass_InitForHouse, 0x6)
17 | {
18 | 	R->EAX(isNODSidebar);
19 | 	return 0x652EB7;
20 | }
21 | 
22 | DEFINE_HOOK(0x6A5090, SidebarClass_InitPositions, 0x5)
23 | {
24 | 	R->EAX(isNODSidebar);
25 | 	return 0x6A509B;
26 | }
27 | 
28 | DEFINE_HOOK(0x6A51E9, SidebarClass_InitGUI, 0x6)
29 | {
30 | 	DWORD& SidebarClass__OBJECT_HEIGHT = *reinterpret_cast(0xB0B500);
31 | 	SidebarClass__OBJECT_HEIGHT = 0x32;
32 | 
33 | 	R->ESI(isNODSidebar);
34 | 	R->EDX(isNODSidebar);
35 | 	return 0x6A5205;
36 | }
37 | 
38 | // PowerBar Positions
39 | DEFINE_HOOK(0x63FB5D, PowerClass_DrawIt, 0x6)
40 | {
41 | 	R->EAX(isNODSidebar);
42 | 	return 0x63FB63;
43 | }
44 | 
45 | // PowerBar Tooltip Positions
46 | DEFINE_HOOK(0x6403DF, PowerClass_InitGUI, 0x6)
47 | {
48 | 	R->ESI(isNODSidebar);
49 | 	return 0x6403E5;
50 | }
51 | 


--------------------------------------------------------------------------------
/src/Ext/Side/Hooks.cpp:
--------------------------------------------------------------------------------
 1 | #include "Body.h"
 2 | #include 
 3 | #include 
 4 | 
 5 | // Ingame music switch when defeated
 6 | DEFINE_HOOK_AGAIN(0x4FCB7D, HouseClass_WinLoseTheme, 0x5)  // HouseClass::Flag_To_Win
 7 | DEFINE_HOOK(0x4FCD66, HouseClass_WinLoseTheme, 0x5)        // HouseClass::Flag_To_Lose
 8 | {
 9 | 	HouseClass* pThis = HouseClass::CurrentPlayer;
10 | 	SideClass* pSide = SideClass::Array.GetItemOrDefault(pThis->SideIndex);
11 | 	auto pSideExt = SideExt::ExtMap.Find(pSide);
12 | 
13 | 	if (pSideExt)
14 | 	{
15 | 		int themeIndex = (pThis->IsWinner) ? pSideExt->IngameScore_WinTheme : pSideExt->IngameScore_LoseTheme;
16 | 		if (themeIndex >= 0)
17 | 			ThemeClass::Instance.Play(themeIndex);
18 | 	}
19 | 
20 | 	return 0;
21 | }
22 | 


--------------------------------------------------------------------------------
/src/Ext/Sidebar/Body.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | 
 3 | #include 
 4 | 
 5 | #include 
 6 | #include 
 7 | #include 
 8 | 
 9 | #include 
10 | 
11 | class SidebarExt
12 | {
13 | public:
14 | 	using base_type = SidebarClass;
15 | 
16 | 	static constexpr DWORD Canary = 0x51DEBA12;
17 | 
18 | 	class ExtData final : public Extension
19 | 	{
20 | 	public:
21 | 
22 | 		ExtData(SidebarClass* OwnerObject) : Extension(OwnerObject)
23 | 		{ }
24 | 
25 | 		virtual ~ExtData() = default;
26 | 
27 | 		virtual void InvalidatePointer(void* ptr, bool bRemoved) override { }
28 | 
29 | 		virtual void LoadFromStream(PhobosStreamReader& Stm) override;
30 | 		virtual void SaveToStream(PhobosStreamWriter& Stm) override;
31 | 	private:
32 | 		template 
33 | 		void Serialize(T& Stm);
34 | 	};
35 | 
36 | private:
37 | 	static std::unique_ptr Data;
38 | 
39 | public:
40 | 	static IStream* g_pStm;
41 | 
42 | 	static SHPStruct* TabProducingProgress[4];
43 | 
44 | 	static void Allocate(SidebarClass* pThis);
45 | 	static void Remove(SidebarClass* pThis);
46 | 
47 | 	static ExtData* Global()
48 | 	{
49 | 		return Data.get();
50 | 	}
51 | 
52 | 	static void Clear()
53 | 	{
54 | 		Allocate(&SidebarClass::Instance);
55 | 	}
56 | 
57 | 	static void PointerGotInvalid(void* ptr, bool removed)
58 | 	{
59 | 		Global()->InvalidatePointer(ptr, removed);
60 | 	}
61 | 
62 | 	static bool __stdcall AresTabCameo_RemoveCameo(BuildType* pItem);
63 | };
64 | 


--------------------------------------------------------------------------------
/src/Ext/Sidebar/SWSidebar/SWButtonClass.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | #include 
 3 | 
 4 | class SWButtonClass : public ControlClass
 5 | {
 6 | public:
 7 | 	SWButtonClass() = default;
 8 | 	SWButtonClass(unsigned int id, int superIdx, int x, int y, int width, int height);
 9 | 
10 | 	~SWButtonClass() = default;
11 | 
12 | 	virtual bool Draw(bool forced) override;
13 | 	virtual void OnMouseEnter() override;
14 | 	virtual void OnMouseLeave() override;
15 | 	virtual bool Action(GadgetFlag fags, DWORD* pKey, KeyModifier modifier) override;
16 | 
17 | 	void SetColumn(int column);
18 | 	bool LaunchSuper() const;
19 | 
20 | public:
21 | 	static constexpr int StartID = 2200;
22 | 
23 | 	bool IsHovering { false };
24 | 	int ColumnIndex { -1 };
25 | 	int SuperIndex { -1 };
26 | };
27 | 


--------------------------------------------------------------------------------
/src/Ext/Sidebar/SWSidebar/SWColumnClass.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | #include "SWButtonClass.h"
 3 | #include 
 4 | 
 5 | #include 
 6 | 
 7 | class SWColumnClass : public ControlClass
 8 | {
 9 | public:
10 | 	SWColumnClass() = default;
11 | 	SWColumnClass(unsigned int id, int maxButtons, int x, int y, int width, int height);
12 | 
13 | 	~SWColumnClass() = default;
14 | 
15 | 	virtual bool Draw(bool forced) override;
16 | 	virtual void OnMouseEnter() override;
17 | 	virtual void OnMouseLeave() override;
18 | 	virtual bool Clicked(DWORD* pKey, GadgetFlag flags, int x, int y, KeyModifier modifier) override;
19 | 
20 | 	bool AddButton(int superIdx);
21 | 	bool RemoveButton(int superIdx);
22 | 	void ClearButtons(bool remove = true);
23 | 
24 | 	void SetHeight(int height);
25 | 
26 | 	std::vector Buttons {};
27 | 	int MaxButtons { 0 };
28 | };
29 | 


--------------------------------------------------------------------------------
/src/Ext/Sidebar/SWSidebar/SWSidebarClass.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | #include "SWButtonClass.h"
 3 | #include "SWColumnClass.h"
 4 | #include "ToggleSWButtonClass.h"
 5 | #include 
 6 | #include 
 7 | 
 8 | class SWSidebarClass
 9 | {
10 | public:
11 | 	bool AddColumn();
12 | 	bool RemoveColumn();
13 | 
14 | 	void InitClear();
15 | 	void InitIO();
16 | 
17 | 	bool AddButton(int superIdx);
18 | 	void SortButtons();
19 | 
20 | 	int GetMaximumButtonCount();
21 | 
22 | 	static bool IsEnabled();
23 | 	static void RecheckCameo();
24 | 
25 | 	static SWSidebarClass Instance;
26 | 
27 | public:
28 | 	std::vector Columns {};
29 | 	SWColumnClass* CurrentColumn { nullptr };
30 | 	SWButtonClass* CurrentButton { nullptr };
31 | 	ToggleSWButtonClass* ToggleButton { nullptr };
32 | 	bool DisableEntry { false };
33 | 
34 | 	static CommandClass* Commands[10];
35 | };
36 | 


--------------------------------------------------------------------------------
/src/Ext/Sidebar/SWSidebar/ToggleSWButtonClass.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | #include 
 3 | 
 4 | class ToggleSWButtonClass : public ControlClass
 5 | {
 6 | public:
 7 | 	ToggleSWButtonClass() = default;
 8 | 	ToggleSWButtonClass(unsigned int id, int x, int y, int width, int height);
 9 | 
10 | 	~ToggleSWButtonClass() = default;
11 | 
12 | 	virtual bool Draw(bool forced) override;
13 | 	virtual void OnMouseEnter() override;
14 | 	virtual void OnMouseLeave() override;
15 | 	virtual bool Action(GadgetFlag fags, DWORD* pKey, KeyModifier modifier) override;
16 | 
17 | 	void UpdatePosition();
18 | 
19 | 	static bool SwitchSidebar();
20 | 
21 | public:
22 | 	bool IsHovering { false };
23 | 	bool IsPressed { false };
24 | };
25 | 


--------------------------------------------------------------------------------
/src/Ext/Surface/Body.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | 
 3 | #include 
 4 | 
 5 | class SurfaceExt : public Surface
 6 | {
 7 | public:
 8 | 	void BlurRect(const RectangleStruct& rect, float blurSize);
 9 | 
10 | };
11 | 


--------------------------------------------------------------------------------
/src/Ext/TAction/Body.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | 
 3 | #include 
 4 | #include 
 5 | 
 6 | #include 
 7 | 
 8 | #include 
 9 | 
10 | class HouseClass;
11 | 
12 | enum class PhobosTriggerAction : unsigned int
13 | {
14 | 	SaveGame = 500,
15 | 	EditVariable = 501,
16 | 	GenerateRandomNumber = 502,
17 | 	PrintVariableValue = 503,
18 | 	BinaryOperation = 504,
19 | 	RunSuperWeaponAtLocation = 505,
20 | 	RunSuperWeaponAtWaypoint = 506,
21 | 	ToggleMCVRedeploy = 510,
22 | 
23 | 	EditAngerNode = 606,
24 | 	ClearAngerNode = 607,
25 | 	SetForceEnemy = 608,
26 | };
27 | 
28 | class TActionExt
29 | {
30 | public:
31 | 	using base_type = TActionClass;
32 | 
33 | 	static constexpr DWORD Canary = 0x91919191;
34 | 
35 | 	class ExtData final : public Extension
36 | 	{
37 | 	public:
38 | 		ExtData(TActionClass* const OwnerObject) : Extension(OwnerObject)
39 | 		{ }
40 | 
41 | 		virtual ~ExtData() = default;
42 | 
43 | 		virtual void InvalidatePointer(void* ptr, bool bRemoved) override { }
44 | 
45 | 		virtual void LoadFromStream(PhobosStreamReader& Stm) override;
46 | 		virtual void SaveToStream(PhobosStreamWriter& Stm) override;
47 | 
48 | 	private:
49 | 		template 
50 | 		void Serialize(T& Stm);
51 | 	};
52 | 
53 | 	static bool Execute(TActionClass* pThis, HouseClass* pHouse,
54 | 			ObjectClass* pObject, TriggerClass* pTrigger, CellStruct const& location, bool& bHandled);
55 | 
56 | #pragma push_macro("ACTION_FUNC")
57 | #define ACTION_FUNC(name) \
58 | 	static bool name(TActionClass* pThis, HouseClass* pHouse, \
59 | 		ObjectClass* pObject, TriggerClass* pTrigger, CellStruct const& location)
60 | 
61 | 	ACTION_FUNC(PlayAudioAtRandomWP);
62 | 	ACTION_FUNC(SaveGame);
63 | 	ACTION_FUNC(EditVariable);
64 | 	ACTION_FUNC(GenerateRandomNumber);
65 | 	ACTION_FUNC(PrintVariableValue);
66 | 	ACTION_FUNC(BinaryOperation);
67 | 	ACTION_FUNC(RunSuperWeaponAtLocation);
68 | 	ACTION_FUNC(RunSuperWeaponAtWaypoint);
69 | 	ACTION_FUNC(ToggleMCVRedeploy);
70 | 
71 | 	ACTION_FUNC(EditAngerNode);
72 | 	ACTION_FUNC(ClearAngerNode);
73 | 	ACTION_FUNC(SetForceEnemy);
74 | 
75 | 	static bool RunSuperWeaponAt(TActionClass* pThis, int X, int Y);
76 | 
77 | #undef ACTION_FUNC
78 | #pragma pop_macro("ACTION_FUNC")
79 | 
80 | 	class ExtContainer final : public Container
81 | 	{
82 | 	public:
83 | 		ExtContainer();
84 | 		~ExtContainer();
85 | 	};
86 | 
87 | 	static ExtContainer ExtMap;
88 | };
89 | 


--------------------------------------------------------------------------------
/src/Ext/TEvent/Hooks.cpp:
--------------------------------------------------------------------------------
 1 | #include "Body.h"
 2 | 
 3 | #include 
 4 | 
 5 | #include 
 6 | #include 
 7 | #include 
 8 | #include 
 9 | #include 
10 | 
11 | #include 
12 | 
13 | DEFINE_HOOK(0x71E940, TEventClass_Execute, 0x5)
14 | {
15 | 	GET(TEventClass*, pThis, ECX);
16 | 	GET_STACK(int, iEvent, 0x4); // now trigger what?
17 | 	GET_STACK(HouseClass*, pHouse, 0x8);
18 | 	GET_STACK(ObjectClass*, pObject, 0xC);
19 | 	GET_STACK(CDTimerClass*, pTimer, 0x10);
20 | 	GET_STACK(bool*, isPersitant, 0x14);
21 | 	GET_STACK(TechnoClass*, pSource, 0x18);
22 | 
23 | 	const auto result = TEventExt::Execute(pThis, iEvent, pHouse, pObject, pTimer, isPersitant, pSource);
24 | 
25 | 	if (!result.has_value())
26 | 		return 0;
27 | 
28 | 	R->AL(result.value());
29 | 	return 0x71EA2D;
30 | }
31 | 
32 | DEFINE_HOOK(0x7271F9, TEventClass_GetFlags, 0x5)
33 | {
34 | 	GET(int, eAttach, EAX);
35 | 	GET(TEventClass*, pThis, ESI);
36 | 
37 | 	int nEvent = static_cast(pThis->EventKind);
38 | 	if (nEvent >= PhobosTriggerEvent::LocalVariableGreaterThan && nEvent < PhobosTriggerEvent::_DummyMaximum)
39 | 	{
40 | 		eAttach |= TEventExt::GetFlags(nEvent);
41 | 	}
42 | 
43 | 	R->EAX(eAttach);
44 | 
45 | 	return 0;
46 | }
47 | 
48 | DEFINE_HOOK(0x71F3FE, TEventClass_BuildINIEntry, 0x5)
49 | {
50 | 	GET(int, eNeedType, EAX);
51 | 	GET(TEventClass*, pThis, ECX);
52 | 
53 | 	int nEvent = static_cast(pThis->EventKind);
54 | 	if (nEvent >= PhobosTriggerEvent::LocalVariableGreaterThan && nEvent < PhobosTriggerEvent::_DummyMaximum)
55 | 		eNeedType = 43;
56 | 
57 | 	R->EAX(eNeedType);
58 | 
59 | 	return 0;
60 | }
61 | 
62 | DEFINE_HOOK(0x726577, TEventClass_Persistable, 0x7)
63 | {
64 | 	GET(TEventClass*, pThis, EDI);
65 | 
66 | 	int nEvent = static_cast(pThis->EventKind);
67 | 	if (nEvent >= PhobosTriggerEvent::LocalVariableGreaterThan && nEvent < PhobosTriggerEvent::_DummyMaximum)
68 | 		R->AL(true);
69 | 	else
70 | 		R->AL(pThis->GetStateB());
71 | 
72 | 	return 0x72657E;
73 | }
74 | 


--------------------------------------------------------------------------------
/src/Ext/Team/Body.cpp:
--------------------------------------------------------------------------------
 1 | #include "Body.h"
 2 | 
 3 | TeamExt::ExtContainer TeamExt::ExtMap;
 4 | 
 5 | // =============================
 6 | // load / save
 7 | 
 8 | template 
 9 | void TeamExt::ExtData::Serialize(T& Stm)
10 | {
11 | 	Stm
12 | 		.Process(this->WaitNoTargetAttempts)
13 | 		.Process(this->NextSuccessWeightAward)
14 | 		.Process(this->IdxSelectedObjectFromAIList)
15 | 		.Process(this->CloseEnough)
16 | 		.Process(this->Countdown_RegroupAtLeader)
17 | 		.Process(this->MoveMissionEndMode)
18 | 		.Process(this->WaitNoTargetCounter)
19 | 		.Process(this->WaitNoTargetTimer)
20 | 		.Process(this->ForceJump_Countdown)
21 | 		.Process(this->ForceJump_InitialCountdown)
22 | 		.Process(this->ForceJump_RepeatMode)
23 | 		.Process(this->TeamLeader)
24 | 		.Process(this->PreviousScriptList)
25 | 		;
26 | }
27 | 
28 | void TeamExt::ExtData::LoadFromStream(PhobosStreamReader& Stm)
29 | {
30 | 	Extension::LoadFromStream(Stm);
31 | 	this->Serialize(Stm);
32 | }
33 | 
34 | void TeamExt::ExtData::SaveToStream(PhobosStreamWriter& Stm)
35 | {
36 | 	Extension::SaveToStream(Stm);
37 | 	this->Serialize(Stm);
38 | }
39 | 
40 | void TeamExt::ExtData::InvalidatePointer(void* ptr, bool bRemoved)
41 | {
42 | 	AnnounceInvalidPointer(TeamLeader, ptr);
43 | }
44 | 
45 | // =============================
46 | // container
47 | 
48 | TeamExt::ExtContainer::ExtContainer() : Container("TeamClass") { }
49 | TeamExt::ExtContainer::~ExtContainer() = default;
50 | 
51 | // =============================
52 | // container hooks
53 | 
54 | //Everything InitEd beside the Vector below this address
55 | DEFINE_HOOK(0x6E8B46, TeamClass_CTOR, 0x7)
56 | {
57 | 	GET(TeamClass*, pThis, ESI);
58 | 
59 | 	TeamExt::ExtMap.TryAllocate(pThis);
60 | 
61 | 	return 0;
62 | }
63 | 
64 | //before `test` i hope not crash the game ,..
65 | DEFINE_HOOK(0x6E8EC6, TeamClass_DTOR, 0x9)
66 | {
67 | 	GET(TeamClass*, pThis, ESI);
68 | 
69 | 	TeamExt::ExtMap.Remove(pThis);
70 | 
71 | 	return 0;
72 | }
73 | 
74 | DEFINE_HOOK_AGAIN(0x6EC450, TeamClass_SaveLoad_Prefix, 0x5)
75 | DEFINE_HOOK(0x6EC540, TeamClass_SaveLoad_Prefix, 0x8)
76 | {
77 | 	GET_STACK(TeamClass*, pItem, 0x4);
78 | 	GET_STACK(IStream*, pStm, 0x8);
79 | 
80 | 	TeamExt::ExtMap.PrepareStream(pItem, pStm);
81 | 
82 | 	return 0;
83 | }
84 | 
85 | DEFINE_HOOK(0x6EC52F, TeamClass_Load_Suffix, 0x6)
86 | {
87 | 	TeamExt::ExtMap.LoadStatic();
88 | 
89 | 	return 0;
90 | }
91 | 
92 | DEFINE_HOOK(0x6EC55A, TeamClass_Save_Suffix, 0x5)
93 | {
94 | 	TeamExt::ExtMap.SaveStatic();
95 | 	return 0;
96 | }
97 | 


--------------------------------------------------------------------------------
/src/Ext/Team/Body.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | #include 
 3 | 
 4 | #include 
 5 | #include 
 6 | #include 
 7 | #include 
 8 | #include 
 9 | 
10 | class TeamExt
11 | {
12 | public:
13 | 	using base_type = TeamClass;
14 | 
15 | 	static constexpr DWORD Canary = 0x414B4B41;
16 | 	static constexpr size_t ExtPointerOffset = 0x18;
17 | 	static constexpr bool ShouldConsiderInvalidatePointer = true;
18 | 
19 | 	class ExtData final : public Extension
20 | 	{
21 | 	public:
22 | 		int WaitNoTargetAttempts;
23 | 		double NextSuccessWeightAward;
24 | 		int IdxSelectedObjectFromAIList;
25 | 		double CloseEnough;
26 | 		int Countdown_RegroupAtLeader;
27 | 		int MoveMissionEndMode;
28 | 		int WaitNoTargetCounter;
29 | 		CDTimerClass WaitNoTargetTimer;
30 | 		CDTimerClass ForceJump_Countdown;
31 | 		int ForceJump_InitialCountdown;
32 | 		bool ForceJump_RepeatMode;
33 | 		FootClass* TeamLeader;
34 | 		std::vector PreviousScriptList;
35 | 
36 | 		ExtData(TeamClass* OwnerObject) : Extension(OwnerObject)
37 | 			, WaitNoTargetAttempts { 0 }
38 | 			, NextSuccessWeightAward { 0 }
39 | 			, IdxSelectedObjectFromAIList { -1 }
40 | 			, CloseEnough { -1 }
41 | 			, Countdown_RegroupAtLeader { -1 }
42 | 			, MoveMissionEndMode { 0 }
43 | 			, WaitNoTargetCounter { 0 }
44 | 			, WaitNoTargetTimer { }
45 | 			, ForceJump_Countdown { }
46 | 			, ForceJump_InitialCountdown { -1 }
47 | 			, ForceJump_RepeatMode { false }
48 | 			, TeamLeader { nullptr }
49 | 			, PreviousScriptList { }
50 | 		{ }
51 | 
52 | 		virtual ~ExtData() = default;
53 | 
54 | 		virtual void InvalidatePointer(void* ptr, bool bRemoved) override;
55 | 
56 | 		virtual void LoadFromStream(PhobosStreamReader& Stm) override;
57 | 		virtual void SaveToStream(PhobosStreamWriter& Stm) override;
58 | 
59 | 	private:
60 | 		template 
61 | 		void Serialize(T& Stm);
62 | 	};
63 | 
64 | 	class ExtContainer final : public Container
65 | 	{
66 | 	public:
67 | 		ExtContainer();
68 | 		~ExtContainer();
69 | 
70 | 		virtual bool InvalidateExtDataIgnorable(void* const ptr) const override
71 | 		{
72 | 			auto const abs = static_cast(ptr)->WhatAmI();
73 | 
74 | 			switch (abs)
75 | 			{
76 | 			case AbstractType::Infantry:
77 | 			case AbstractType::Unit:
78 | 			case AbstractType::Aircraft:
79 | 				return false;
80 | 			}
81 | 
82 | 			return true;
83 | 		}
84 | 	};
85 | 
86 | 	static ExtContainer ExtMap;
87 | 
88 | };
89 | 


--------------------------------------------------------------------------------
/src/Ext/Team/Hooks.cpp:
--------------------------------------------------------------------------------
 1 | #include "Body.h"
 2 | #include 
 3 | 
 4 | // Bugfix: TAction 7,80,107.
 5 | DEFINE_HOOK(0x65DF67, TeamTypeClass_CreateMembers_LoadOntoTransport, 0x6)
 6 | {
 7 | 	if(!AresHelper::CanUseAres) // If you're not using Ares you don't deserve a fix
 8 | 		return 0;
 9 | 
10 | 	GET(FootClass* const, pPayload, EAX);
11 | 	GET(FootClass* const, pTransport, ESI);
12 | 	GET(TeamClass* const, pTeam, EBP);
13 | 	GET(TeamTypeClass const*, pThis, EBX);
14 | 
15 | 	auto unmarkPayloadCreated = [](FootClass* member){reinterpret_cast(member->align_154)[0x9E] = false;};
16 | 
17 | 	if (!pTransport)
18 | 	{
19 | 		for (auto pNext = pPayload;
20 | 		pNext && pNext != pTransport && pNext->Team == pTeam;
21 | 		pNext = abstract_cast(pNext->NextObject))
22 | 			unmarkPayloadCreated(pNext);
23 | 
24 | 		return 0x65DFE8;
25 | 	}
26 | 
27 | 	unmarkPayloadCreated(pTransport);
28 | 
29 | 	if (!pPayload || !pThis->Full)
30 | 		return 0x65E004;
31 | 
32 | 	const auto pType = pTransport->GetTechnoType();
33 | 	const bool isTransportOpenTopped = pType->OpenTopped;
34 | 	FootClass* pGunner = nullptr;
35 | 
36 | 	for (auto pNext = pPayload;
37 | 		pNext && pNext != pTransport && pNext->Team == pTeam;
38 | 		pNext = abstract_cast(pNext->NextObject))
39 | 	{
40 | 		pPayload->Transporter = pTransport;
41 | 		pGunner = pNext;
42 | 
43 | 		if (isTransportOpenTopped)
44 | 			pTransport->EnteredOpenTopped(pNext);
45 | 	}
46 | 
47 | 	// Add to transport - this will load the payload object and everything linked to it (rest of the team) in reverse order
48 | 	pTransport->Passengers.AddPassenger(pPayload);
49 | 
50 | 	// Handle gunner change - this is the 'last' passenger because of reverse order
51 | 	if (pType->Gunner && pGunner)
52 | 		pTransport->ReceiveGunner(pGunner);
53 | 
54 | 	return 0x65DF8D;
55 | }
56 | 


--------------------------------------------------------------------------------
/src/Ext/TerrainType/Body.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | #include 
 3 | 
 4 | #include 
 5 | #include 
 6 | #include 
 7 | #include 
 8 | 
 9 | class TerrainTypeExt
10 | {
11 | public:
12 | 	using base_type = TerrainTypeClass;
13 | 
14 | 	static constexpr DWORD Canary = 0xBEE78007;
15 | 	static constexpr size_t ExtPointerOffset = 0x18;
16 | 
17 | 	class ExtData final : public Extension
18 | 	{
19 | 	public:
20 | 		Valueable SpawnsTiberium_Type;
21 | 		Valueable SpawnsTiberium_Range;
22 | 		Valueable> SpawnsTiberium_GrowthStage;
23 | 		Valueable> SpawnsTiberium_CellsPerAnim;
24 | 		Valueable DestroyAnim;
25 | 		ValueableIdx DestroySound;
26 | 		Nullable MinimapColor;
27 | 		Valueable IsPassable;
28 | 		Valueable CanBeBuiltOn;
29 | 		Valueable HasDamagedFrames;
30 | 		Valueable HasCrumblingFrames;
31 | 		ValueableIdx CrumblingSound;
32 | 		Nullable AnimationLength;
33 | 
34 | 		PhobosFixedString<32u> PaletteFile;
35 | 		DynamicVectorClass* Palette; // Intentionally not serialized - rebuilt from the palette file on load.
36 | 
37 | 		ExtData(TerrainTypeClass* OwnerObject) : Extension(OwnerObject)
38 | 			, SpawnsTiberium_Type { 0 }
39 | 			, SpawnsTiberium_Range { 1 }
40 | 			, SpawnsTiberium_GrowthStage { { 3, 0 } }
41 | 			, SpawnsTiberium_CellsPerAnim { { 1, 0 } }
42 | 			, DestroyAnim {}
43 | 			, DestroySound {}
44 | 			, MinimapColor {}
45 | 			, IsPassable { false }
46 | 			, CanBeBuiltOn { false }
47 | 			, HasDamagedFrames { false }
48 | 			, HasCrumblingFrames { false }
49 | 			, CrumblingSound {}
50 | 			, AnimationLength {}
51 | 			, PaletteFile {}
52 | 			, Palette {}
53 | 		{ }
54 | 
55 | 		virtual ~ExtData() = default;
56 | 
57 | 		virtual void LoadFromINIFile(CCINIClass* pINI) override;
58 | 
59 | 		virtual void InvalidatePointer(void* ptr, bool bRemoved) override { }
60 | 
61 | 		virtual void LoadFromStream(PhobosStreamReader& Stm) override;
62 | 		virtual void SaveToStream(PhobosStreamWriter& Stm) override;
63 | 
64 | 		int GetTiberiumGrowthStage();
65 | 		int GetCellsPerAnim();
66 | 		void PlayDestroyEffects(const CoordStruct& coords);
67 | 
68 | 	private:
69 | 		template 
70 | 		void Serialize(T& Stm);
71 | 	};
72 | 
73 | 	class ExtContainer final : public Container
74 | 	{
75 | 	public:
76 | 		ExtContainer();
77 | 		~ExtContainer();
78 | 	};
79 | 
80 | 	static ExtContainer ExtMap;
81 | 
82 | 	static bool LoadGlobals(PhobosStreamReader& Stm);
83 | 	static bool SaveGlobals(PhobosStreamWriter& Stm);
84 | 
85 | 	static void Remove(TerrainClass* pTerrain);
86 | };
87 | 


--------------------------------------------------------------------------------
/src/Ext/Tiberium/Body.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | #include 
 3 | 
 4 | #include 
 5 | #include 
 6 | #include 
 7 | #include 
 8 | #include 
 9 | 
10 | class TiberiumExt
11 | {
12 | public:
13 | 	using base_type = TiberiumClass;
14 | 
15 | 	static constexpr DWORD Canary = 0xAABBCCDD;
16 | 	static constexpr size_t ExtPointerOffset = 0x18;
17 | 
18 | 	class ExtData final : public Extension
19 | 	{
20 | 	public:
21 | 		Nullable MinimapColor;
22 | 
23 | 		ExtData(TiberiumClass* OwnerObject) : Extension(OwnerObject)
24 | 			, MinimapColor {}
25 | 		{ }
26 | 
27 | 		virtual ~ExtData() = default;
28 | 
29 | 		virtual void LoadFromINIFile(CCINIClass* pINI) override;
30 | 
31 | 		virtual void InvalidatePointer(void* ptr, bool bRemoved) override { }
32 | 
33 | 		virtual void LoadFromStream(PhobosStreamReader& Stm) override;
34 | 		virtual void SaveToStream(PhobosStreamWriter& Stm) override;
35 | 
36 | 	private:
37 | 		template 
38 | 		void Serialize(T& Stm);
39 | 	};
40 | 
41 | 	class ExtContainer final : public Container
42 | 	{
43 | 	public:
44 | 		ExtContainer();
45 | 		~ExtContainer();
46 | 	};
47 | 
48 | 	static ExtContainer ExtMap;
49 | 
50 | 	static bool LoadGlobals(PhobosStreamReader& Stm);
51 | 	static bool SaveGlobals(PhobosStreamWriter& Stm);
52 | };
53 | 


--------------------------------------------------------------------------------
/src/Ext/Tiberium/Hooks.cpp:
--------------------------------------------------------------------------------
 1 | #include "Body.h"
 2 | 
 3 | #include 
 4 | #include 
 5 | 
 6 | #include 
 7 | 
 8 | DEFINE_HOOK(0x47C210, CellClass_CellColor_TiberiumRadarColor, 0x6)
 9 | {
10 | 	enum { ReturnFromFunction = 0x47C23F };
11 | 
12 | 	GET(CellClass*, pThis, ESI);
13 | 	GET_STACK(ColorStruct*, arg0, STACK_OFFSET(0x14, 0x4));
14 | 	GET_STACK(ColorStruct*, arg4, STACK_OFFSET(0x14, 0x8));
15 | 
16 | 	int tiberiumType = OverlayClass::GetTiberiumType(pThis->OverlayTypeIndex);
17 | 
18 | 	if (tiberiumType < 0)
19 | 		return 0;
20 | 
21 | 	auto pTiberium = TiberiumClass::Array.GetItem(tiberiumType);
22 | 
23 | 	if (const auto pTiberiumExt = TiberiumExt::ExtMap.Find(pTiberium))
24 | 	{
25 | 		if (pTiberiumExt->MinimapColor.isset())
26 | 		{
27 | 			auto& color = pTiberiumExt->MinimapColor.Get();
28 | 
29 | 			arg0->R = color.R;
30 | 			arg0->G = color.G;
31 | 			arg0->B = color.B;
32 | 
33 | 			arg4->R = color.R;
34 | 			arg4->G = color.G;
35 | 			arg4->B = color.B;
36 | 
37 | 			R->ECX(arg4);
38 | 			R->AL(color.B);
39 | 
40 | 			return ReturnFromFunction;
41 | 		}
42 | 	}
43 | 
44 | 	return 0;
45 | }
46 | 


--------------------------------------------------------------------------------
/src/Ext/Trigger/Hooks.cpp:
--------------------------------------------------------------------------------
 1 | #include 
 2 | 
 3 | #include 
 4 | 
 5 | #include 
 6 | 
 7 | DEFINE_HOOK(0x727064, TriggerTypeClass_HasLocalSetOrClearedEvent, 0x5)
 8 | {
 9 | 	GET(const int, nIndex, EDX);
10 | 
11 | 	return
12 | 		nIndex >= PhobosTriggerEvent::LocalVariableGreaterThan && nIndex <= PhobosTriggerEvent::LocalVariableAndIsTrue ||
13 | 		nIndex >= PhobosTriggerEvent::LocalVariableGreaterThanLocalVariable && nIndex >= PhobosTriggerEvent::LocalVariableAndIsTrueLocalVariable ||
14 | 		nIndex >= PhobosTriggerEvent::LocalVariableGreaterThanGlobalVariable && nIndex >= PhobosTriggerEvent::LocalVariableAndIsTrueGlobalVariable ||
15 | 		nIndex == static_cast(TriggerEvent::LocalSet) ?
16 | 		0x72706E :
17 | 		0x727069;
18 | }
19 | 
20 | DEFINE_HOOK(0x727024, TriggerTypeClass_HasGlobalSetOrClearedEvent, 0x5)
21 | {
22 | 	GET(const int, nIndex, EDX);
23 | 
24 | 	return
25 | 		nIndex >= PhobosTriggerEvent::GlobalVariableGreaterThan && nIndex <= PhobosTriggerEvent::GlobalVariableAndIsTrue ||
26 | 		nIndex >= PhobosTriggerEvent::GlobalVariableGreaterThanLocalVariable && nIndex >= PhobosTriggerEvent::GlobalVariableAndIsTrueLocalVariable ||
27 | 		nIndex >= PhobosTriggerEvent::GlobalVariableGreaterThanGlobalVariable && nIndex >= PhobosTriggerEvent::GlobalVariableAndIsTrueGlobalVariable ||
28 | 		nIndex == static_cast(TriggerEvent::GlobalSet) ?
29 | 		0x72702E :
30 | 		0x727029;
31 | }
32 | 


--------------------------------------------------------------------------------
/src/Ext/Unit/Hooks.DeployFire.cpp:
--------------------------------------------------------------------------------
 1 | #include 
 2 | 
 3 | #include 
 4 | #include 
 5 | 
 6 | // issue #112 Make FireOnce=yes work on other TechnoTypes
 7 | // Author: Starkku
 8 | DEFINE_HOOK(0x4C7512, EventClass_Execute_StopUnitDeployFire, 0x6)
 9 | {
10 | 	GET(TechnoClass* const, pThis, ESI);
11 | 
12 | 	auto const pUnit = abstract_cast(pThis);
13 | 	if (pUnit && pUnit->CurrentMission == Mission::Unload && pUnit->Type->DeployFire && !pUnit->Type->IsSimpleDeployer)
14 | 	{
15 | 		pUnit->SetTarget(nullptr);
16 | 		pThis->QueueMission(Mission::Guard, true);
17 | 	}
18 | 
19 | 	return 0;
20 | }
21 | 
22 | DEFINE_HOOK(0x4C77E4, EventClass_Execute_UnitDeployFire, 0x6)
23 | {
24 | 	enum { DoNotExecute = 0x4C8109 };
25 | 
26 | 	GET(TechnoClass* const, pThis, ESI);
27 | 
28 | 	auto const pUnit = abstract_cast(pThis);
29 | 
30 | 	// Do not execute deploy command if the vehicle has only just fired its once-firing deploy weapon.
31 | 	if (pUnit && pUnit->Type->DeployFire && !pUnit->Type->IsSimpleDeployer)
32 | 	{
33 | 		int weaponIndex = -1;
34 | 		auto const pWeapon = TechnoExt::GetDeployFireWeapon(pThis, weaponIndex);
35 | 
36 | 		if (pWeapon && pWeapon->FireOnce)
37 | 		{
38 | 			const auto pExt = TechnoExt::ExtMap.Find(pThis);
39 | 
40 | 			if (pExt->DeployFireTimer.HasTimeLeft())
41 | 				return DoNotExecute;
42 | 		}
43 | 	}
44 | 
45 | 	return 0;
46 | }
47 | 
48 | DEFINE_HOOK(0x73DCEF, UnitClass_Mission_Unload_DeployFire, 0x6)
49 | {
50 | 	enum { SkipGameCode = 0x73DD3C };
51 | 
52 | 	GET(UnitClass*, pThis, ESI);
53 | 
54 | 	int weaponIndex = -1;
55 | 	auto const pWeapon = TechnoExt::GetDeployFireWeapon(pThis, weaponIndex);
56 | 
57 | 	if (weaponIndex < 0 || !pWeapon)
58 | 	{
59 | 		pThis->QueueMission(Mission::Guard, true);
60 | 		return SkipGameCode;
61 | 	}
62 | 
63 | 	auto pCell = MapClass::Instance.GetCellAt(pThis->GetMapCoords());
64 | 	pThis->SetTarget(pCell);
65 | 
66 | 	if (pThis->GetFireError(pCell, weaponIndex, true) == FireError::OK)
67 | 	{
68 | 		pThis->Fire(pThis->Target, weaponIndex);
69 | 
70 | 		if (pWeapon->FireOnce)
71 | 		{
72 | 			pThis->SetTarget(nullptr);
73 | 			pThis->QueueMission(Mission::Guard, true);
74 | 			const auto pExt = TechnoExt::ExtMap.Find(pThis);
75 | 			const auto UnloadControl = &MissionControlClass::Array[(int)Mission::Unload];
76 | 			int delay = static_cast(UnloadControl->Rate * 900) + ScenarioClass::Instance->Random(0, 2);
77 | 			pExt->DeployFireTimer.Start(Math::min(pWeapon->ROF, delay));
78 | 		}
79 | 	}
80 | 
81 | 	return SkipGameCode;
82 | }
83 | 


--------------------------------------------------------------------------------
/src/Ext/Unit/Hooks.DisallowMoving.cpp:
--------------------------------------------------------------------------------
 1 | // Issue #5 Permanently stationary units
 2 | // Author: Starkku
 3 | 
 4 | #include "UnitClass.h"
 5 | 
 6 | #include 
 7 | #include 
 8 | 
 9 | DEFINE_HOOK(0x740A93, UnitClass_Mission_Move_DisallowMoving, 0x6)
10 | {
11 | 	GET(UnitClass*, pThis, ESI);
12 | 
13 | 	return pThis->Type->Speed == 0 ? 0x740AEF : 0;
14 | }
15 | 
16 | DEFINE_HOOK(0x741AA7, UnitClass_Assign_Destination_DisallowMoving, 0x6)
17 | {
18 | 	GET(UnitClass*, pThis, EBP);
19 | 
20 | 	return pThis->Type->Speed == 0 ? 0x743173 : 0;
21 | }
22 | 
23 | DEFINE_HOOK(0x743B4B, UnitClass_Scatter_DisallowMoving, 0x6)
24 | {
25 | 	GET(UnitClass*, pThis, EBP);
26 | 
27 | 	return pThis->Type->Speed == 0 ? 0x74408E : 0;
28 | }
29 | 
30 | DEFINE_HOOK(0x74038F, UnitClass_What_Action_ObjectClass_DisallowMoving_1, 0x6)
31 | {
32 | 	GET(UnitClass*, pThis, ESI);
33 | 
34 | 	return pThis->Type->Speed == 0 ? 0x7403A3 : 0;
35 | }
36 | 
37 | DEFINE_HOOK(0x7403B7, UnitClass_What_Action_ObjectClass_DisallowMoving_2, 0x6)
38 | {
39 | 	GET(UnitClass*, pThis, ESI);
40 | 
41 | 	return pThis->Type->Speed == 0 ? 0x7403C1 : 0;
42 | }
43 | 
44 | DEFINE_HOOK(0x740709, UnitClass_What_Action_DisallowMoving_1, 0x6)
45 | {
46 | 	GET(UnitClass*, pThis, ESI);
47 | 
48 | 	return pThis->Type->Speed == 0 ? 0x740727 : 0;
49 | }
50 | 
51 | DEFINE_HOOK(0x740744, UnitClass_What_Action_DisallowMoving_2, 0x6)
52 | {
53 | 	enum { AllowAttack = 0x74078E, ReturnNoMove = 0x740769, ReturnResult = 0x740801 };
54 | 
55 | 	GET(UnitClass*, pThis, ESI);
56 | 	GET_STACK(Action, result, 0x30);
57 | 
58 | 	if (pThis->Type->Speed == 0)
59 | 	{
60 | 		if (result == Action::Move)
61 | 			return ReturnNoMove;
62 | 		if (result != Action::Attack)
63 | 			return ReturnResult;
64 | 
65 | 		return AllowAttack;
66 | 	}
67 | 
68 | 	return 0;
69 | }
70 | 
71 | DEFINE_HOOK(0x736B60, UnitClass_Rotation_AI_DisallowMoving, 0x6)
72 | {
73 | 	GET(UnitClass*, pThis, ESI);
74 | 
75 | 	return pThis->Type->Speed == 0 ? 0x736AFB : 0;
76 | }
77 | 
78 | DEFINE_HOOK(0x73891D, UnitClass_Active_Click_With_DisallowMoving, 0x6)
79 | {
80 | 	GET(UnitClass*, pThis, ESI);
81 | 
82 | 	return pThis->Type->Speed == 0 ? 0x738927 : 0;
83 | }
84 | 


--------------------------------------------------------------------------------
/src/Ext/Unit/Hooks.Harvester.cpp:
--------------------------------------------------------------------------------
 1 | #include 
 2 | #include 
 3 | 
 4 | #include 
 5 | 
 6 | DEFINE_HOOK(0x73E411, UnitClass_Mission_Unload_DumpAmount, 0x7)
 7 | {
 8 | 	enum { SkipGameCode = 0x73E41D };
 9 | 
10 | 	GET(UnitClass*, pThis, ESI);
11 | 	GET(int, tiberiumIdx, EBP);
12 | 	const auto pTypeExt = TechnoTypeExt::ExtMap.Find(pThis->Type);
13 | 	const float totalAmount = pThis->Tiberium.GetAmount(tiberiumIdx);
14 | 	float dumpAmount = pTypeExt->HarvesterDumpAmount.Get(RulesExt::Global()->HarvesterDumpAmount);
15 | 
16 | 	if (dumpAmount <= 0.0f || totalAmount < dumpAmount)
17 | 		dumpAmount = totalAmount;
18 | 
19 | 	__asm fld dumpAmount;
20 | 
21 | 	return SkipGameCode;
22 | }
23 | 
24 | DEFINE_HOOK(0x4D6D34, FootClass_MissionAreaGuard_Miner, 0x5)
25 | {
26 | 	enum { GoGuardArea = 0x4D6D69 };
27 | 
28 | 	GET(FootClass*, pThis, ESI);
29 | 
30 | 	auto const pTypeExt = TechnoTypeExt::ExtMap.Find(pThis->GetTechnoType());
31 | 
32 | 	return pTypeExt->Harvester_CanGuardArea && pThis->Owner->IsControlledByHuman() ? GoGuardArea : 0;
33 | }
34 | 
35 | #pragma region HarvesterScanAfterUnload
36 | 
37 | DEFINE_HOOK(0x73E730, UnitClass_MissionHarvest_HarvesterScanAfterUnload, 0x5)
38 | {
39 | 	GET(UnitClass* const, pThis, EBP);
40 | 	GET(AbstractClass* const, pFocus, EAX);
41 | 
42 | 	auto pType = pThis->Type;
43 | 	// Focus is set when the harvester is fully loaded and go home.
44 | 	if (pFocus && !pType->Weeder && TechnoTypeExt::ExtMap.Find(pType)->HarvesterScanAfterUnload.Get(RulesExt::Global()->HarvesterScanAfterUnload))
45 | 	{
46 | 		auto cellBuffer = CellStruct::Empty;
47 | 		const auto pCellStru = pThis->ScanForTiberium(&cellBuffer, RulesClass::Instance->TiberiumLongScan / Unsorted::LeptonsPerCell, 0);
48 | 
49 | 		if (*pCellStru != CellStruct::Empty)
50 | 		{
51 | 			const auto pCell = MapClass::Instance.TryGetCellAt(*pCellStru);
52 | 			const auto distFromTiberium = pCell ? pThis->DistanceFrom(pCell) : -1;
53 | 			const auto distFromFocus = pThis->DistanceFrom(pFocus);
54 | 
55 | 			// Check if pCell is better than focus.
56 | 			if (distFromTiberium > 0 && distFromTiberium < distFromFocus)
57 | 				R->EAX(pCell);
58 | 		}
59 | 	}
60 | 
61 | 	return 0;
62 | }
63 | 
64 | #pragma endregion
65 | 


--------------------------------------------------------------------------------
/src/Ext/Unit/Hooks.Sinking.cpp:
--------------------------------------------------------------------------------
 1 | #include 
 2 | 
 3 | #include 
 4 | #include 
 5 | #include 
 6 | 
 7 | #include 
 8 | 
 9 | DEFINE_HOOK(0x7364DC, UnitClass_Update_SinkSpeed, 0x7)
10 | {
11 | 	GET(UnitClass* const, pThis, ESI);
12 | 	GET(int, CoordZ, EDX);
13 | 
14 | 	auto const pTypeExt = TechnoTypeExt::ExtMap.Find(pThis->Type);
15 | 	R->EDX(CoordZ - (pTypeExt->SinkSpeed - 5));
16 | 	return 0;
17 | }
18 | 
19 | DEFINE_HOOK(0x737DE2, UnitClass_ReceiveDamage_Sinkable, 0x6)
20 | {
21 | 	enum { GoOtherChecks = 0x737E18, NoSink = 0x737E63 };
22 | 
23 | 	GET(UnitTypeClass*, pType, EAX);
24 | 
25 | 	auto const pTypeExt = TechnoTypeExt::ExtMap.Find(pType);
26 | 	bool ShouldSink = pType->Weight > RulesClass::Instance->ShipSinkingWeight && pType->Naval && !pType->Underwater && !pType->Organic;
27 | 
28 | 	return pTypeExt->Sinkable.Get(ShouldSink) ? GoOtherChecks : NoSink;
29 | }
30 | 
31 | DEFINE_HOOK(0x629C67, ParasiteClass_UpdateSquid_SinkableBySquid, 0x9)
32 | {
33 | 	enum { ret = 0x629C86 };
34 | 
35 | 	GET(ParasiteClass*, pThis, ESI);
36 | 	GET(FootClass*, pVictim, EDI);
37 | 
38 | 	auto pVictimType = pVictim->GetTechnoType();
39 | 	auto pVictimTypeExt = TechnoTypeExt::ExtMap.Find(pVictimType);
40 | 
41 | 	if (pVictimTypeExt->Sinkable_SquidGrab || pVictim->WhatAmI() != AbstractType::Unit)
42 | 	{
43 | 		pVictim->IsSinking = true;
44 | 		pVictim->Destroyed(pThis->Owner);
45 | 		pVictim->Stun();
46 | 	}
47 | 	else
48 | 	{
49 | 		auto damage = pVictimType->Strength;
50 | 		pVictim->ReceiveDamage(&damage, 0, RulesClass::Instance->C4Warhead, pThis->Owner, true, false, pThis->Owner->Owner);
51 | 	}
52 | 
53 | 	return ret;
54 | }
55 | 


--------------------------------------------------------------------------------
/src/Ext/VoxelAnim/Body.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | 
 3 | #include 
 4 | 
 5 | #include 
 6 | #include 
 7 | #include 
 8 | #include 
 9 | #include 
10 | 
11 | #include 
12 | 
13 | #include 
14 | 
15 | class VoxelAnimExt
16 | {
17 | public:
18 | 	using base_type = VoxelAnimClass;
19 | 
20 | 	static constexpr DWORD Canary = 0xAAAAAACC;
21 | 	static constexpr size_t ExtPointerOffset = 0x18;
22 | 
23 | 	class ExtData final : public Extension
24 | 	{
25 | 	public:
26 | 
27 | 		std::vector LaserTrails;
28 | 
29 | 		ExtData(VoxelAnimClass* OwnerObject) : Extension(OwnerObject)
30 | 			, LaserTrails()
31 | 		{ }
32 | 
33 | 		virtual ~ExtData() = default;
34 | 		virtual void InvalidatePointer(void* ptr, bool bRemoved) override { }
35 | 		virtual void LoadFromStream(PhobosStreamReader& Stm)override;
36 | 		virtual void SaveToStream(PhobosStreamWriter& Stm)override;
37 | 		virtual void Initialize() override;
38 | 
39 | 	private:
40 | 		template 
41 | 		void Serialize(T& Stm);
42 | 	};
43 | 
44 | 	class ExtContainer final : public Container
45 | 	{
46 | 	public:
47 | 		ExtContainer();
48 | 		~ExtContainer();
49 | 	};
50 | 
51 | 	static ExtContainer ExtMap;
52 | 	static void InitializeLaserTrails(VoxelAnimClass* pThis);
53 | 	static bool LoadGlobals(PhobosStreamReader& Stm);
54 | 	static bool SaveGlobals(PhobosStreamWriter& Stm);
55 | };
56 | 


--------------------------------------------------------------------------------
/src/Ext/VoxelAnim/Hooks.cpp:
--------------------------------------------------------------------------------
 1 | #include "Body.h"
 2 | 
 3 | #include 
 4 | 
 5 | #include 
 6 | #include 
 7 | #include 
 8 | #include 
 9 | 
10 | DEFINE_HOOK(0x74A70E, VoxelAnimClass_AI_Additional, 0xC)
11 | {
12 | 	GET(VoxelAnimClass* const, pThis, EBX);
13 | 
14 | 	//auto pTypeExt = VoxelAnimTypeExt::ExtMap.Find(pThis->Type);
15 | 	auto pThisExt = VoxelAnimExt::ExtMap.Find(pThis);
16 | 
17 | 	if (!pThisExt->LaserTrails.empty())
18 | 	{
19 | 		CoordStruct location = pThis->GetCoords();
20 | 		CoordStruct drawnCoords = location;
21 | 
22 | 		for (auto& trail : pThisExt->LaserTrails)
23 | 		{
24 | 			if (!trail.LastLocation.isset())
25 | 				trail.LastLocation = location;
26 | 
27 | 			trail.Visible = pThis->IsVisible;
28 | 			trail.Update(drawnCoords);
29 | 
30 | 		}
31 | 	}
32 | 
33 | 	return 0;
34 | }
35 | 
36 | DEFINE_HOOK(0x74A027, VoxelAnimClass_AI_Expired, 0x6)
37 | {
38 | 	enum { SkipGameCode = 0x74A22A };
39 | 
40 | 	GET(VoxelAnimClass* const, pThis, EBX);
41 | 	GET(int, flag, EAX);
42 | 
43 | 	bool heightFlag = flag & 0xFF;
44 | 
45 | 	if (!pThis || !pThis->Type)
46 | 		return SkipGameCode;
47 | 
48 | 	auto const pType = pThis->Type;
49 | 	auto const pTypeExt = VoxelAnimTypeExt::ExtMap.Find(pType);
50 | 	auto const splashAnims = pTypeExt->SplashAnims.GetElements(RulesClass::Instance->SplashList);
51 | 
52 | 	AnimExt::HandleDebrisImpact(pType->ExpireAnim, pTypeExt->WakeAnim, splashAnims, pThis->OwnerHouse, pType->Warhead, pType->Damage,
53 | 		pThis->GetCell(), pThis->Location, heightFlag, pType->IsMeteor, pTypeExt->Warhead_Detonate, pTypeExt->ExplodeOnWater, pTypeExt->SplashAnims_PickRandom);
54 | 
55 | 	return SkipGameCode;
56 | }
57 | 


--------------------------------------------------------------------------------
/src/Ext/VoxelAnimType/Body.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | #include 
 3 | 
 4 | #include 
 5 | #include 
 6 | #include 
 7 | #include 
 8 | #include 
 9 | #include 
10 | 
11 | #include 
12 | 
13 | class VoxelAnimTypeExt
14 | {
15 | public:
16 | 	using base_type = VoxelAnimTypeClass;
17 | 
18 | 	static constexpr DWORD Canary = 0xAAAEEEEE;
19 | 	static constexpr size_t ExtPointerOffset = 0x18;
20 | 
21 | 	class ExtData final : public Extension
22 | 	{
23 | 	public:
24 | 
25 | 		ValueableIdxVector LaserTrail_Types;
26 | 		Valueable ExplodeOnWater;
27 | 		Valueable Warhead_Detonate;
28 | 		Valueable WakeAnim;
29 | 		NullableVector SplashAnims;
30 | 		Valueable SplashAnims_PickRandom;
31 | 
32 | 		ExtData(VoxelAnimTypeClass* OwnerObject) : Extension(OwnerObject)
33 | 			, LaserTrail_Types()
34 | 			, ExplodeOnWater { false }
35 | 			, Warhead_Detonate { false }
36 | 			, WakeAnim {}
37 | 			, SplashAnims {}
38 | 			, SplashAnims_PickRandom { false }
39 | 		{ }
40 | 
41 | 		virtual ~ExtData() = default;
42 | 		virtual void LoadFromINIFile(CCINIClass* pINI) override;
43 | 
44 | 		virtual void InvalidatePointer(void* ptr, bool bRemoved) override { }
45 | 
46 | 		virtual void Initialize() override;
47 | 		virtual void LoadFromStream(PhobosStreamReader& Stm)override;
48 | 		virtual void SaveToStream(PhobosStreamWriter& Stm)override;
49 | 
50 | 	private:
51 | 		template 
52 | 		void Serialize(T& Stm);
53 | 	};
54 | 
55 | 	class ExtContainer final : public Container
56 | 	{
57 | 	public:
58 | 		ExtContainer();
59 | 		~ExtContainer();
60 | 	};
61 | 
62 | 	static ExtContainer ExtMap;
63 | 
64 | 	static bool LoadGlobals(PhobosStreamReader& Stm);
65 | 	static bool SaveGlobals(PhobosStreamWriter& Stm);
66 | };
67 | 


--------------------------------------------------------------------------------
/src/Ext/WeaponType/Hooks.DiskLaserRadius.cpp:
--------------------------------------------------------------------------------
 1 | #include "Body.h"
 2 | 
 3 | double WeaponTypeExt::OldRadius = DiskLaserClass::Radius;
 4 | // 0x4A6CF0 :
 5 | // Angles = [int((i*360/16+270)%360) for i in range(0,16)] = [270, 292, 315, 337, 0, 22, 45, 67, 90, 112, 135, 157, 180, 202, 235, 257] (except the last 2)
 6 | // DrawCoords = [( int(np.cos(np.pi/180*deg) * 240), int(np.sin(np.pi/180*deg) * 240) )  for deg in Angles]
 7 | constexpr double Cos16Sects[16]
 8 | {
 9 | 	0.0, 0.37460659341591196, 0.7071067811865474, 0.9205048534524403,
10 | 	1.0, 0.9271838545667874, 0.7071067811865476, 0.3907311284892737,
11 | 	0.0, -0.37460659341591207, -0.7071067811865475, -0.9205048534524404,
12 | 	-1.0, -0.9271838545667874, -0.5735764363510464, -0.22495105434386525
13 | };
14 | 
15 | constexpr double Sin16Sects[16]
16 | {
17 | 	-1.0, -0.9271838545667874, -0.7071067811865477, -0.3907311284892739,
18 | 	0.0, 0.374606593415912, 0.7071067811865476, 0.9205048534524404,
19 | 	1.0, 0.9271838545667874, 0.7071067811865476, 0.39073112848927377,
20 | 	0.0, -0.374606593415912, -0.8191520442889916, -0.9743700647852351
21 | };
22 | 
23 | DEFINE_HOOK(0x4A757B, DiskLaser_Circle, 0x6)
24 | {
25 | 	GET(WeaponTypeClass*, pWeapon, EDX);
26 | 
27 | 	auto const pTypeData = WeaponTypeExt::ExtMap.Find(pWeapon);
28 | 
29 | 	if (pTypeData && WeaponTypeExt::OldRadius != pTypeData->DiskLaser_Radius)
30 | 	{
31 | 		double newRadius = pTypeData->DiskLaser_Radius;
32 | 		WeaponTypeExt::OldRadius = newRadius;
33 | 
34 | 		for (int i = 0; i < 16; i++)
35 | 		{
36 | 			DiskLaserClass::DrawCoords[i].X = (int)(Cos16Sects[i] * newRadius);
37 | 			DiskLaserClass::DrawCoords[i].Y = (int)(Sin16Sects[i] * newRadius);
38 | 		}
39 | 	}
40 | 	return 0;
41 | }
42 | 


--------------------------------------------------------------------------------
/src/Ext/WeaponType/Hooks.cpp:
--------------------------------------------------------------------------------
 1 | #include "Body.h"
 2 | 
 3 | #include 
 4 | 
 5 | DEFINE_HOOK(0x772A0A, WeaponTypeClass_SetSpeed_ApplyGravity, 0x6)
 6 | {
 7 | 	GET(BulletTypeClass* const, pType, EAX);
 8 | 
 9 | 	auto const nGravity = BulletTypeExt::GetAdjustedGravity(pType);
10 | 	__asm { fld nGravity };
11 | 
12 | 	return 0x772A29;
13 | }
14 | 
15 | DEFINE_HOOK(0x773087, WeaponTypeClass_GetSpeed_ApplyGravity, 0x6)
16 | {
17 | 	GET(BulletTypeClass* const, pType, EAX);
18 | 
19 | 	auto const nGravity = BulletTypeExt::GetAdjustedGravity(pType);
20 | 	__asm { fld nGravity };
21 | 
22 | 	return 0x7730A3;
23 | }
24 | 
25 | DEFINE_HOOK(0x772AA2, WeaponTypeClass_AllowedThreats_AAOnly, 0x5)
26 | {
27 | 	GET(BulletTypeClass* const, pType, ECX);
28 | 
29 | 	if (BulletTypeExt::ExtMap.Find(pType)->AAOnly)
30 | 	{
31 | 		R->EAX(4);
32 | 		return 0x772AB3;
33 | 	}
34 | 
35 | 	return 0;
36 | }
37 | 


--------------------------------------------------------------------------------
/src/Misc/BlittersFix.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | 
3 | class BlittersFix
4 | {
5 | public:
6 | 	static void Apply();
7 | };
8 | 


--------------------------------------------------------------------------------
/src/Misc/FlyingStrings.h:
--------------------------------------------------------------------------------
 1 | /*FlyingStrings.h
 2 | Useable to get out messages from units
 3 | Used to output Bounty messages
 4 | By AlexB and Joshy
 5 | */
 6 | 
 7 | #pragma once
 8 | #include 
 9 | #include 
10 | #include 
11 | #include 
12 | 
13 | class FlyingStrings
14 | {
15 | private:
16 | 
17 | 	struct Item
18 | 	{
19 | 		CoordStruct Location;
20 | 		Point2D PixelOffset;
21 | 		int CreationFrame;
22 | 		wchar_t Text[0x20];
23 | 		COLORREF Color;
24 | 
25 | 	};
26 | 
27 | 	static const int Duration = 75;
28 | 	static std::vector Data;
29 | 
30 | 	static bool DrawAllowed(CoordStruct& nCoords);
31 | 
32 | public:
33 | 	static void Add(const wchar_t* text, const CoordStruct& coords, ColorStruct color, Point2D pixelOffset = Point2D::Empty);
34 | 	static void AddMoneyString(int amount, HouseClass* owner, AffectedHouse displayToHouses, const CoordStruct& coords, Point2D pixelOffset = Point2D::Empty);
35 | 	static void UpdateAll();
36 | };
37 | 


--------------------------------------------------------------------------------
/src/Misc/Hooks.LaserDraw.cpp:
--------------------------------------------------------------------------------
 1 | #include 
 2 | 
 3 | #include 
 4 | #include 
 5 | #include 
 6 | #include 
 7 | #include 
 8 | 
 9 | namespace LaserDrawTemp
10 | {
11 | 	ColorStruct maxColor;
12 | }
13 | 
14 | DEFINE_HOOK(0x550D1F, LaserDrawClass_DrawInHouseColor_Context_Set, 0x6)
15 | {
16 | 	LaserDrawTemp::maxColor = ColorStruct(*R->lea_Stack(0x14));
17 | 	return 0;
18 | }
19 | 
20 | //Enables proper laser thickness and falloff of it
21 | DEFINE_HOOK(0x550F47, LaserDrawClass_DrawInHouseColor_BetterDrawing, 0x0)
22 | {
23 | 	// Restore overridden code that's needed - Kerbiter
24 | 	GET_STACK(bool, noQuickDraw, 0x13);
25 | 	R->ESI(noQuickDraw ? 8u : 64u);
26 | 
27 | 	GET(LaserDrawClass*, pThis, EBX);
28 | 	GET_STACK(int, currentThickness, 0x5C);
29 | 
30 | 	double mult = 1.0;
31 | 
32 | 	if (pThis->Thickness > 1)
33 | 	{
34 | 		double falloffStep = 1.0 / pThis->Thickness;
35 | 		double falloffMult = GeneralUtils::FastPow(1.0 - falloffStep, currentThickness);
36 | 		mult = (1.0 - falloffStep * currentThickness) * falloffMult;
37 | 	}
38 | 
39 | 	unsigned int r = (unsigned int)(mult * LaserDrawTemp::maxColor.R);
40 | 	unsigned int g = (unsigned int)(mult * LaserDrawTemp::maxColor.G);
41 | 	unsigned int b = (unsigned int)(mult * LaserDrawTemp::maxColor.B);
42 | 
43 | 	R->EAX(r);
44 | 	R->ECX(g);
45 | 	R->EDX(b);
46 | 
47 | 	return 0x550F9D;
48 | }
49 | 


--------------------------------------------------------------------------------
/src/Misc/Hooks.LightEffects.cpp:
--------------------------------------------------------------------------------
 1 | #include 
 2 | 
 3 | #include 
 4 | #include 
 5 | 
 6 | namespace LightEffectsTemp
 7 | {
 8 | 	bool AlphaIsLightFlash = false;
 9 | }
10 | 
11 | DEFINE_HOOK(0x48A444, AreaDamage_Particle_LightFlashSet, 0x5)
12 | {
13 | 	GET(WarheadTypeClass*, pWH, EDI);
14 | 
15 | 	auto const pWHExt = WarheadTypeExt::ExtMap.Find(pWH);
16 | 
17 | 	if (pWHExt->Particle_AlphaImageIsLightFlash.Get(RulesExt::Global()->WarheadParticleAlphaImageIsLightFlash))
18 | 		LightEffectsTemp::AlphaIsLightFlash = true;
19 | 
20 | 	return 0;
21 | }
22 | 
23 | DEFINE_HOOK(0x48A47E, AreaDamage_Particle_LightFlashUnset, 0x6)
24 | {
25 | 	LightEffectsTemp::AlphaIsLightFlash = false;
26 | 
27 | 	return 0;
28 | }
29 | 
30 | DEFINE_HOOK(0x5F5053, ObjectClass_Unlimbo_AlphaImage, 0x6)
31 | {
32 | 	enum { SkipAlphaImage = 0x5F514B };
33 | 
34 | 	int detailLevel = 0;
35 | 
36 | 	if (LightEffectsTemp::AlphaIsLightFlash)
37 | 	{
38 | 		if (Phobos::Config::HideLightFlashEffects)
39 | 			return SkipAlphaImage;
40 | 
41 | 		detailLevel = RulesExt::Global()->LightFlashAlphaImageDetailLevel;
42 | 	}
43 | 
44 | 	if (detailLevel > GameOptionsClass::Instance.DetailLevel)
45 | 		return SkipAlphaImage;
46 | 
47 | 	return 0;
48 | }
49 | 
50 | DEFINE_HOOK(0x48A62E, DoFlash_CombatLightOptions, 0x6)
51 | {
52 | 	enum { Continue = 0x48A64A, SkipFlash = 0x48A6FA };
53 | 
54 | 	if (Phobos::Config::HideLightFlashEffects)
55 | 		return SkipFlash;
56 | 
57 | 	GET(WarheadTypeClass*, pWH, EDI);
58 | 	GET(int, currentDetailLevel, EAX);
59 | 	GET(int, damage, ECX);
60 | 
61 | 	R->ESI(damage); // Restore overridden instructions.
62 | 	int detailLevel = RulesExt::Global()->CombatLightDetailLevel;
63 | 
64 | 	if (pWH)
65 | 	{
66 | 		auto const pWHExt = WarheadTypeExt::ExtMap.Find(pWH);
67 | 		detailLevel = pWHExt->CombatLightDetailLevel.Get(detailLevel);
68 | 
69 | 		if (pWHExt->CombatLightChance < Randomizer::Global.RandomDouble())
70 | 			return SkipFlash;
71 | 
72 | 		if (pWHExt->CLIsBlack)
73 | 			R->EBX(SpotlightFlags::NoColor);
74 | 	}
75 | 
76 | 	if (detailLevel <= currentDetailLevel)
77 | 		return Continue;
78 | 
79 | 	return SkipFlash;
80 | }
81 | 


--------------------------------------------------------------------------------
/src/Misc/Hooks.SkirmishColors.cpp:
--------------------------------------------------------------------------------
 1 | #include 
 2 | #include 
 3 | #include 
 4 | 
 5 | DEFINE_HOOK(0x69A317, GetLinkedColor_SkirmishUnlimitedColors, 0x0)
 6 | {
 7 | 	GET_STACK(int, index, 0x4);
 8 | 
 9 | 	if (index == -2)
10 | 		index = ColorScheme::FindIndex("LightGrey", 53);
11 | 	else
12 | 		index = index * 2 + 1;
13 | 
14 | 	R->EAX(index);
15 | 
16 | 	return 0x69A325;
17 | }
18 | 


--------------------------------------------------------------------------------
/src/Misc/Hooks.Timers.cpp:
--------------------------------------------------------------------------------
 1 | #include 
 2 | #include 
 3 | #include 
 4 | #include 
 5 | #include 
 6 | 
 7 | #include 
 8 | #include 
 9 | 
10 | namespace TimerValueTemp
11 | {
12 | 	static int oldValue;
13 | };
14 | 
15 | DEFINE_HOOK(0x6D4B50, PrintTimerOnTactical_Start, 0x6)
16 | {
17 | 	if (!Phobos::Config::RealTimeTimers)
18 | 		return 0;
19 | 
20 | 	REF_STACK(int, value, STACK_OFFSET(0, 0x4));
21 | 	TimerValueTemp::oldValue = value;
22 | 
23 | 	if (Phobos::Config::RealTimeTimers_Adaptive
24 | 		|| GameOptionsClass::Instance.GameSpeed == 0
25 | 		|| (Phobos::Misc::CustomGS && !SessionClass::IsMultiplayer()))
26 | 	{
27 | 		value = (int)((double)value / (std::max((double)FPSCounter::CurrentFrameRate, 1.0) / 15.0));
28 | 		return 0;
29 | 	}
30 | 
31 | 	switch (GameOptionsClass::Instance.GameSpeed)
32 | 	{
33 | 	case 1:	// 60 FPS
34 | 		value = value / 4;
35 | 		break;
36 | 	case 2:	// 30 FPS
37 | 		value = value / 2;
38 | 		break;
39 | 	case 3:	// 20 FPS
40 | 		value = (value * 3) / 4;
41 | 		break;
42 | 	case 4:	// 15 FPS
43 | 		break;
44 | 	case 5:	// 12 FPS
45 | 		value = (value * 5) / 4;
46 | 		break;
47 | 	case 6:	// 10 FPS
48 | 		value = (value * 3) / 2;
49 | 		break;
50 | 	default:
51 | 		break;
52 | 	}
53 | 
54 | 	return 0;
55 | }
56 | 
57 | DEFINE_HOOK(0x6D4C68, PrintTimerOnTactical_End, 0x8)
58 | {
59 | 	if (!Phobos::Config::RealTimeTimers)
60 | 		return 0;
61 | 
62 | 	REF_STACK(int, value, STACK_OFFSET(0x654, 0x4));
63 | 	value = TimerValueTemp::oldValue;
64 | 	return 0;
65 | }
66 | 
67 | DEFINE_HOOK(0x6D4CD9, PrintTimerOnTactical_BlinkColor, 0x6)
68 | {
69 | 	enum { SkipGameCode = 0x6D4CE2 };
70 | 
71 | 	R->EDI(ColorScheme::Array.GetItem(RulesExt::Global()->TimerBlinkColorScheme));
72 | 
73 | 	return SkipGameCode;
74 | }
75 | 


--------------------------------------------------------------------------------
/src/Misc/PhobosToolTip.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | 
 3 | #include 
 4 | #include 
 5 | #include 
 6 | 
 7 | #include 
 8 | 
 9 | #include 
10 | #include 
11 | 
12 | #include 
13 | 
14 | struct StripClass;
15 | 
16 | class PhobosToolTip
17 | {
18 | public:
19 | 	static PhobosToolTip Instance;
20 | 
21 | private:
22 | 	inline const wchar_t* GetUIDescription(TechnoTypeExt::ExtData* pData) const;
23 | 	inline const wchar_t* GetUIDescription(SWTypeExt::ExtData* pData) const;
24 | 	inline int GetBuildTime(TechnoTypeClass* pType) const;
25 | 	inline int GetPower(TechnoTypeClass* pType) const;
26 | 
27 | public:
28 | 	inline bool IsEnabled() const;
29 | 	inline const wchar_t* GetBuffer() const;
30 | 
31 | 	void HelpText(BuildType& cameo);
32 | 	void HelpText_Techno(TechnoTypeClass* pType);
33 | 	void HelpText_Super(int swidx);
34 | 
35 | 	// Properties
36 | private:
37 | 	std::wstring TextBuffer {};
38 | 
39 | public:
40 | 	bool IsCameo { false };
41 | 	bool SlaveDraw { false };
42 | };
43 | 


--------------------------------------------------------------------------------
/src/Misc/RetryDialog.cpp:
--------------------------------------------------------------------------------
 1 | #include 
 2 | #include 
 3 | #include 
 4 | #include 
 5 | #include 
 6 | #include 
 7 | #include 
 8 | #include 
 9 | 
10 | namespace RetryDialogFlag
11 | {
12 | 	bool IsCalledFromRetryDialog = false;
13 | }
14 | 
15 | DEFINE_HOOK(0x686092, DoLose_RetryDialogForCampaigns, 0x7)
16 | {
17 | 	enum { OK = 0x6860F6, Cancel = 0x6860EE, LoadGame = 0x686231 };
18 | 
19 | 	while (true)
20 | 	{
21 | 		// WWMessageBox buttons look like below:
22 | 		// Button1
23 | 		// Button3
24 | 		// Button2
25 | 		// I prefer to put the loadgame to the center of them - secsome
26 | 		// Did you??? NO, YOU DIDN'T. Bruhhhh
27 | 		switch (WWMessageBox::Instance.Process(
28 | 			GameStrings::TXT_TO_REPLAY,
29 | 			"GUI:LOADGAME",
30 | 			GameStrings::TXT_CANCEL,
31 | 			GameStrings::TXT_OK))
32 | 		{
33 | 		case WWMessageBox::Result::Button3:
34 | 			return OK;
35 | 
36 | 		default:
37 | 		case WWMessageBox::Result::Button2:
38 | 			return Cancel;
39 | 
40 | 		case WWMessageBox::Result::Button1:
41 | 			auto pDialog = GameCreate();
42 | 			RetryDialogFlag::IsCalledFromRetryDialog = true;
43 | 			const bool bIsAboutToLoad = pDialog->LoadDialog();
44 | 			RetryDialogFlag::IsCalledFromRetryDialog = false;
45 | 			GameDelete(pDialog);
46 | 
47 | 			if (!bIsAboutToLoad)
48 | 				continue;
49 | 
50 | 			ThemeClass::Instance.Stop();
51 | 			break;
52 | 		}
53 | 
54 | 		break;
55 | 	}
56 | 
57 | 	EvadeClass::Instance.Do();
58 | 
59 | 	if (CCToolTip::Instance)
60 | 		CCToolTip::Instance->SetState(GameOptionsClass::Instance.Tooltips);
61 | 
62 | 	GScreenClass::Instance.Render();
63 | 
64 | 	return LoadGame;
65 | }
66 | 
67 | DEFINE_HOOK(0x558F4E, LoadOptionClass_Dialog_CenterListBox, 0x5)
68 | {
69 | 	if (RetryDialogFlag::IsCalledFromRetryDialog)
70 | 	{
71 | 		GET(HWND, hListBox, EAX);
72 | 		GET(HWND, hDialog, EDI);
73 | 
74 | 		HWND hLoadButton = GetDlgItem(hDialog, 1039);
75 | 
76 | 		RECT buttonRect;
77 | 		GetWindowRect(hLoadButton, &buttonRect);
78 | 
79 | 		float scaleX = static_cast(buttonRect.right - buttonRect.left) / 108;
80 | 		float scaleY = static_cast(buttonRect.bottom - buttonRect.top) / 22;
81 | 		int X = buttonRect.left - static_cast(346 * scaleX);
82 | 		int Y = buttonRect.top - static_cast(44 * scaleY);
83 | 
84 | 		SetWindowPos(hListBox, NULL, X, Y, NULL, NULL, SWP_NOSIZE | SWP_NOZORDER);
85 | 	}
86 | 
87 | 	return 0;
88 | }
89 | 


--------------------------------------------------------------------------------
/src/Misc/TextInput.cpp:
--------------------------------------------------------------------------------
 1 | #include 
 2 | 
 3 | // Allow message entry in Skirmish
 4 | // DEFINE_JUMP(LJMP, 0x55E484, 0x55E48D);
 5 | 
 6 | wchar_t* IMEBuffer = reinterpret_cast(0xB730EC);
 7 | 
 8 | UINT GetCurentCodepage()
 9 | {
10 | 	char szLCData[6 + 1];
11 | 	WORD lang = LOWORD(GetKeyboardLayout(NULL));
12 | 	LCID locale = MAKELCID(lang, SORT_DEFAULT);
13 | 	GetLocaleInfoA(locale, LOCALE_IDEFAULTANSICODEPAGE, szLCData, _countof(szLCData));
14 | 
15 | 	return atoi(szLCData);
16 | }
17 | 
18 | wchar_t LocalizeCharacter(char character)
19 | {
20 | 	wchar_t result;
21 | 	UINT codepage = GetCurentCodepage();
22 | 	MultiByteToWideChar(codepage, MB_USEGLYPHCHARS, &character, 1, &result, 1);
23 | 	return result;
24 | }
25 | 
26 | DEFINE_HOOK(0x5D46C7, MessageListClass_Input, 0x5)
27 | {
28 | 	if (!IMEBuffer[0])
29 | 		R->EBX(LocalizeCharacter(R->EBX()));
30 | 
31 | 	return 0;
32 | }
33 | 
34 | DEFINE_HOOK(0x61510E, WWUI_NewEditCtrl, 0x7)
35 | {
36 | 	R->EDI(LocalizeCharacter(R->EBX()));
37 | 	return 0x615226;
38 | }
39 | 
40 | // It is required to add Imm32.lib to AdditionalDependencies
41 | /*
42 | HIMC& IMEContext = *reinterpret_cast(0xB7355C);
43 | wchar_t* IMECompositionString = reinterpret_cast(0xB73318);
44 | 
45 | DEFINE_HOOK(0x777F15, IMEUpdateCompositionString, 0x7)
46 | {
47 | 	IMECompositionString[0] = 0;
48 | 	ImmGetCompositionStringW(IMEContext, GCS_COMPSTR, IMECompositionString, 256);
49 | 
50 | 	return 0;
51 | }
52 | */
53 | 


--------------------------------------------------------------------------------
/src/New/Entity/LaserTrailClass.cpp:
--------------------------------------------------------------------------------
 1 | #include "LaserTrailClass.h"
 2 | 
 3 | #include 
 4 | 
 5 | // Draws LaserTrail if the conditions are suitable.
 6 | // Returns true if drawn, false otherwise.
 7 | bool LaserTrailClass::Update(CoordStruct location)
 8 | {
 9 | 	bool result = false;
10 | 
11 | 	if (!this->LastLocation.isset())
12 | 	{
13 | 		// The trail was just inited
14 | 		this->LastLocation = location;
15 | 	}
16 | 	else if (location.DistanceFrom(this->LastLocation.Get()) > this->Type->SegmentLength) // TODO reimplement IgnoreVertical properly?
17 | 	{
18 | 		if (this->Visible && !this->Cloaked && (this->Type->IgnoreVertical ? (abs(location.X - this->LastLocation.Get().X) > 16 || abs(location.Y - this->LastLocation.Get().Y) > 16) : true))
19 | 		{
20 | 			// We spawn new laser segment if the distance is long enough, the game will do the rest - Kerbiter
21 | 			LaserDrawClass* pLaser = GameCreate(
22 | 				this->LastLocation.Get(), location,
23 | 				this->CurrentColor, ColorStruct { 0, 0, 0 }, ColorStruct { 0, 0, 0 },
24 | 				this->Type->FadeDuration.Get());
25 | 
26 | 			pLaser->Thickness = this->Type->Thickness;
27 | 			pLaser->IsHouseColor = true;
28 | 			pLaser->IsSupported = this->Type->IsIntense;
29 | 
30 | 			result = true;
31 | 		}
32 | 
33 | 		this->LastLocation = location;
34 | 	}
35 | 
36 | 	return result;
37 | }
38 | 
39 | #pragma region Save/Load
40 | 
41 | template 
42 | bool LaserTrailClass::Serialize(T& stm)
43 | {
44 | 	return stm
45 | 		.Process(this->Type)
46 | 		.Process(this->Visible)
47 | 		.Process(this->Cloaked)
48 | 		.Process(this->FLH)
49 | 		.Process(this->IsOnTurret)
50 | 		.Process(this->CurrentColor)
51 | 		.Process(this->LastLocation)
52 | 		.Success();
53 | };
54 | 
55 | bool LaserTrailClass::Load(PhobosStreamReader& stm, bool RegisterForChange)
56 | {
57 | 	return Serialize(stm);
58 | }
59 | 
60 | bool LaserTrailClass::Save(PhobosStreamWriter& stm) const
61 | {
62 | 	return const_cast(this)->Serialize(stm);
63 | }
64 | 
65 | #pragma endregion
66 | 


--------------------------------------------------------------------------------
/src/New/Entity/LaserTrailClass.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | 
 3 | #include 
 4 | #include 
 5 | 
 6 | #include 
 7 | 
 8 | 
 9 | class LaserTrailClass
10 | {
11 | public:
12 | 	LaserTrailTypeClass* Type;
13 | 	bool Visible;
14 | 	bool Cloaked;
15 | 	CoordStruct FLH;
16 | 	bool IsOnTurret;
17 | 	ColorStruct CurrentColor;
18 | 	Nullable LastLocation;
19 | 
20 | 	LaserTrailClass(LaserTrailTypeClass* pTrailType, HouseClass* pHouse = nullptr,
21 | 		CoordStruct flh = { 0, 0, 0 }, bool isOnTurret = false) :
22 | 		Type { pTrailType }
23 | 		, Visible { true }
24 | 		, Cloaked { false }
25 | 		, FLH { flh }
26 | 		, IsOnTurret { isOnTurret }
27 | 		, CurrentColor { pTrailType->Color }
28 | 		, LastLocation {}
29 | 	{
30 | 		if (this->Type->IsHouseColor && pHouse)
31 | 			this->CurrentColor = pHouse->LaserColor;
32 | 	}
33 | 
34 | 	LaserTrailClass() :
35 | 		Type {},
36 | 		Visible {},
37 | 		Cloaked {},
38 | 		FLH {},
39 | 		IsOnTurret {},
40 | 		CurrentColor {},
41 | 		LastLocation {}
42 | 	{ }
43 | 
44 | 	bool Update(CoordStruct location);
45 | 
46 | 	bool Load(PhobosStreamReader& stm, bool registerForChange);
47 | 	bool Save(PhobosStreamWriter& stm) const;
48 | 
49 | private:
50 | 	template 
51 | 	bool Serialize(T& stm);
52 | };
53 | 


--------------------------------------------------------------------------------
/src/New/Type/Affiliated/CreateUnitTypeClass.cpp:
--------------------------------------------------------------------------------
 1 | #include "CreateUnitTypeClass.h"
 2 | 
 3 | #include 
 4 | 
 5 | void CreateUnitTypeClass::LoadFromINI(CCINIClass* pINI, const char* pSection)
 6 | {
 7 | 	INI_EX exINI(pINI);
 8 | 
 9 | 	this->Type.Read(exINI, pSection, "CreateUnit");
10 | 	this->Facing.Read(exINI, pSection, "CreateUnit.Facing");
11 | 	this->InheritDeathFacings.Read(exINI, pSection, "CreateUnit.InheritFacings");
12 | 	this->InheritTurretFacings.Read(exINI, pSection, "CreateUnit.InheritTurretFacings");
13 | 	this->RemapAnim.Read(exINI, pSection, "CreateUnit.RemapAnim");
14 | 	this->UnitMission.Read(exINI, pSection, "CreateUnit.Mission");
15 | 	this->AIUnitMission.Read(exINI, pSection, "CreateUnit.AIMission");
16 | 	this->Owner.Read(exINI, pSection, "CreateUnit.Owner");
17 | 	this->RequireOwner.Read(exINI, pSection, "CreateUnit.RequireOwner");
18 | 	this->RandomFacing.Read(exINI, pSection, "CreateUnit.RandomFacing");
19 | 	this->AlwaysSpawnOnGround.Read(exINI, pSection, "CreateUnit.AlwaysSpawnOnGround");
20 | 	this->SpawnParachutedInAir.Read(exINI, pSection, "CreateUnit.SpawnParachutedInAir");
21 | 	this->ConsiderPathfinding.Read(exINI, pSection, "CreateUnit.ConsiderPathfinding");
22 | 	this->SpawnAnim.Read(exINI, pSection, "CreateUnit.SpawnAnim");
23 | 	this->SpawnHeight.Read(exINI, pSection, "CreateUnit.SpawnHeight");
24 | }
25 | 
26 | #pragma region(save/load)
27 | 
28 | template 
29 | bool CreateUnitTypeClass::Serialize(T& stm)
30 | {
31 | 	return stm
32 | 		.Process(this->Type)
33 | 		.Process(this->Facing)
34 | 		.Process(this->InheritDeathFacings)
35 | 		.Process(this->RemapAnim)
36 | 		.Process(this->UnitMission)
37 | 		.Process(this->AIUnitMission)
38 | 		.Process(this->InheritTurretFacings)
39 | 		.Process(this->Owner)
40 | 		.Process(this->RequireOwner)
41 | 		.Process(this->RandomFacing)
42 | 		.Process(this->AlwaysSpawnOnGround)
43 | 		.Process(this->SpawnParachutedInAir)
44 | 		.Process(this->ConsiderPathfinding)
45 | 		.Process(this->SpawnAnim)
46 | 		.Process(this->SpawnHeight)
47 | 		.Success();
48 | }
49 | 
50 | bool CreateUnitTypeClass::Load(PhobosStreamReader& stm, bool registerForChange)
51 | {
52 | 	return this->Serialize(stm);
53 | }
54 | 
55 | bool CreateUnitTypeClass::Save(PhobosStreamWriter& stm) const
56 | {
57 | 	return const_cast(this)->Serialize(stm);
58 | }
59 | 
60 | #pragma endregion(save/load)
61 | 


--------------------------------------------------------------------------------
/src/New/Type/Affiliated/CreateUnitTypeClass.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | 
 3 | #include 
 4 | #include 
 5 | 
 6 | class CreateUnitTypeClass
 7 | {
 8 | public:
 9 | 	Valueable Type { nullptr };
10 | 	Valueable Facing { DirType::North };
11 | 	Valueable InheritDeathFacings { false };
12 | 	Valueable InheritTurretFacings { false };
13 | 	Valueable RandomFacing { true };
14 | 	Valueable RemapAnim { false };
15 | 	Valueable UnitMission { Mission::Guard };
16 | 	Nullable AIUnitMission {};
17 | 	Valueable Owner { OwnerHouseKind::Victim };
18 | 	Valueable RequireOwner { false };
19 | 	Valueable AlwaysSpawnOnGround { false };
20 | 	Valueable SpawnParachutedInAir { false };
21 | 	Valueable ConsiderPathfinding { false };
22 | 	Valueable SpawnAnim { nullptr };
23 | 	Valueable SpawnHeight { -1 };
24 | 
25 | 	CreateUnitTypeClass() = default;
26 | 
27 | 	void LoadFromINI(CCINIClass* pINI, const char* pSection);
28 | 	bool Load(PhobosStreamReader& stm, bool registerForChange);
29 | 	bool Save(PhobosStreamWriter& stm) const;
30 | 
31 | private:
32 | 
33 | 	template 
34 | 	bool Serialize(T& stm);
35 | };
36 | 


--------------------------------------------------------------------------------
/src/New/Type/Affiliated/DroppodTypeClass.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | 
 3 | #include 
 4 | 
 5 | class DroppodTypeClass
 6 | {
 7 | public:
 8 | 	Nullable Speed {};
 9 | 	Nullable Angle {};
10 | 	Nullable Height {};
11 | 	Nullable Weapon {};
12 | 	Nullable GroundAnim[2] { {},{} };
13 | 	Nullable Puff {};
14 | 	Nullable Trailer {};
15 | 	Valueable Trailer_SpawnDelay { 6 };
16 | 	Nullable AtmosphereEntry {};
17 | 	Nullable AirImage { };
18 | 	Valueable Trailer_Attached { false };
19 | 	Valueable Weapon_HitLandOnly { false };
20 | 
21 | 	DroppodTypeClass() = default;
22 | 
23 | 	void LoadFromINI(CCINIClass* pINI, const char* pSection);
24 | 	bool Load(PhobosStreamReader& stm, bool registerForChange);
25 | 	bool Save(PhobosStreamWriter& stm) const;
26 | 
27 | private:
28 | 
29 | 	template 
30 | 	bool Serialize(T& stm);
31 | };
32 | 


--------------------------------------------------------------------------------
/src/New/Type/Affiliated/InterceptorTypeClass.cpp:
--------------------------------------------------------------------------------
 1 | #include "InterceptorTypeClass.h"
 2 | 
 3 | #include 
 4 | #include 
 5 | 
 6 | InterceptorTypeClass::InterceptorTypeClass(TechnoTypeClass* OwnedBy)
 7 | 	: OwnerType { OwnedBy }
 8 | 	, CanTargetHouses { AffectedHouse::Enemies }
 9 | 	, GuardRange {}
10 | 	, MinimumGuardRange {}
11 | 	, Weapon { 0 }
12 | 	, ApplyFirepowerMult { true }
13 | 	, DeleteOnIntercept {}
14 | 	, WeaponOverride {}
15 | 	, WeaponReplaceProjectile { false }
16 | 	, WeaponCumulativeDamage { false }
17 | 	, KeepIntact { false }
18 | { }
19 | 
20 | void InterceptorTypeClass::LoadFromINI(CCINIClass* pINI, const char* pSection)
21 | {
22 | 	INI_EX exINI(pINI);
23 | 
24 | 	this->CanTargetHouses.Read(exINI, pSection, "Interceptor.CanTargetHouses");
25 | 	this->GuardRange.Read(exINI, pSection, "Interceptor.%sGuardRange");
26 | 	this->MinimumGuardRange.Read(exINI, pSection, "Interceptor.%sMinimumGuardRange");
27 | 	this->Weapon.Read(exINI, pSection, "Interceptor.Weapon");
28 | 	this->ApplyFirepowerMult.Read(exINI, pSection, "Interceptor.ApplyFirepowerMult");
29 | 	this->DeleteOnIntercept.Read(exINI, pSection, "Interceptor.DeleteOnIntercept");
30 | 	this->WeaponOverride.Read(exINI, pSection, "Interceptor.WeaponOverride");
31 | 	this->WeaponReplaceProjectile.Read(exINI, pSection, "Interceptor.WeaponReplaceProjectile");
32 | 	this->WeaponCumulativeDamage.Read(exINI, pSection, "Interceptor.WeaponCumulativeDamage");
33 | 	this->KeepIntact.Read(exINI, pSection, "Interceptor.KeepIntact");
34 | }
35 | 
36 | #pragma region(save/load)
37 | 
38 | template 
39 | bool InterceptorTypeClass::Serialize(T& stm)
40 | {
41 | 	return stm
42 | 		.Process(this->OwnerType)
43 | 		.Process(this->CanTargetHouses)
44 | 		.Process(this->GuardRange)
45 | 		.Process(this->MinimumGuardRange)
46 | 		.Process(this->Weapon)
47 | 		.Process(this->ApplyFirepowerMult)
48 | 		.Process(this->DeleteOnIntercept)
49 | 		.Process(this->WeaponOverride)
50 | 		.Process(this->WeaponReplaceProjectile)
51 | 		.Process(this->WeaponCumulativeDamage)
52 | 		.Process(this->KeepIntact)
53 | 		.Success();
54 | }
55 | 
56 | bool InterceptorTypeClass::Load(PhobosStreamReader& stm, bool registerForChange)
57 | {
58 | 	return this->Serialize(stm);
59 | }
60 | 
61 | bool InterceptorTypeClass::Save(PhobosStreamWriter& stm) const
62 | {
63 | 	return const_cast(this)->Serialize(stm);
64 | }
65 | 
66 | #pragma endregion(save/load)
67 | 


--------------------------------------------------------------------------------
/src/New/Type/Affiliated/InterceptorTypeClass.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | 
 3 | #include 
 4 | #include 
 5 | #include 
 6 | 
 7 | class InterceptorTypeClass
 8 | {
 9 | public:
10 | 
11 | 	InterceptorTypeClass() = default;
12 | 
13 | 	InterceptorTypeClass(TechnoTypeClass* OwnedBy);
14 | 
15 | 	TechnoTypeClass* OwnerType;
16 | 
17 | 	Valueable CanTargetHouses;
18 | 	Promotable GuardRange;
19 | 	Promotable MinimumGuardRange;
20 | 	Valueable Weapon;
21 | 	Nullable WeaponOverride;
22 | 	Valueable WeaponReplaceProjectile;
23 | 	Valueable WeaponCumulativeDamage;
24 | 	Valueable KeepIntact;
25 | 	Valueable ApplyFirepowerMult;
26 | 	Nullable DeleteOnIntercept;
27 | 
28 | 	void LoadFromINI(CCINIClass* pINI, const char* pSection);
29 | 	bool Load(PhobosStreamReader& stm, bool registerForChange);
30 | 	bool Save(PhobosStreamWriter& stm) const;
31 | 
32 | private:
33 | 
34 | 	template 
35 | 	bool Serialize(T& stm);
36 | };
37 | 


--------------------------------------------------------------------------------
/src/New/Type/Affiliated/PassengerDeletionTypeClass.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | 
 3 | #include 
 4 | #include 
 5 | #include 
 6 | 
 7 | class PassengerDeletionTypeClass
 8 | {
 9 | public:
10 | 
11 | 	PassengerDeletionTypeClass() = default;
12 | 
13 | 	PassengerDeletionTypeClass(TechnoTypeClass* pOwnerType);
14 | 
15 | 	TechnoTypeClass* OwnerType;
16 | 
17 | 	Valueable Rate;
18 | 	Valueable Rate_SizeMultiply;
19 | 	Valueable UseCostAsRate;
20 | 	Valueable CostMultiplier;
21 | 	Nullable CostRateCap;
22 | 	Valueable AllowedHouses;
23 | 	Valueable DontScore;
24 | 	Valueable Soylent;
25 | 	Valueable SoylentMultiplier;
26 | 	Valueable SoylentAllowedHouses;
27 | 	Valueable DisplaySoylent;
28 | 	Valueable DisplaySoylentToHouses;
29 | 	Valueable DisplaySoylentOffset;
30 | 	ValueableIdx ReportSound;
31 | 	Valueable Anim;
32 | 	Valueable UnderEMP;
33 | 
34 | 	void LoadFromINI(CCINIClass* pINI, const char* pSection);
35 | 	bool Load(PhobosStreamReader& stm, bool registerForChange);
36 | 	bool Save(PhobosStreamWriter& stm) const;
37 | 
38 | 	static std::pair CanParse(INI_EX exINI, const char* pSection);
39 | 
40 | private:
41 | 
42 | 	template 
43 | 	bool Serialize(T& stm);
44 | };
45 | 


--------------------------------------------------------------------------------
/src/New/Type/Affiliated/TiberiumEaterTypeClass.cpp:
--------------------------------------------------------------------------------
 1 | #include "TiberiumEaterTypeClass.h"
 2 | 
 3 | #include 
 4 | #include 
 5 | 
 6 | void TiberiumEaterTypeClass::LoadFromINI(CCINIClass* pINI, const char* pSection)
 7 | {
 8 | 	INI_EX exINI(pINI);
 9 | 	char tempBuffer[32];
10 | 
11 | 	this->TransDelay.Read(exINI, pSection, "TiberiumEater.TransDelay");
12 | 	this->CashMultiplier.Read(exINI, pSection, "TiberiumEater.CashMultiplier");
13 | 	this->AmountPerCell.Read(exINI, pSection, "TiberiumEater.AmountPerCell");
14 | 
15 | 	for (size_t idx = 0; ; ++idx)
16 | 	{
17 | 		Nullable> cell;
18 | 		_snprintf_s(tempBuffer, sizeof(tempBuffer), "TiberiumEater.Cell%d", idx);
19 | 		cell.Read(exINI, pSection, tempBuffer);
20 | 
21 | 		if (idx >= this->Cells.size())
22 | 		{
23 | 			if (!cell.isset())
24 | 				break;
25 | 
26 | 			this->Cells.emplace_back(cell.Get().X * Unsorted::LeptonsPerCell, cell.Get().Y * Unsorted::LeptonsPerCell);
27 | 		}
28 | 		else
29 | 		{
30 | 			if (!cell.isset())
31 | 				continue;
32 | 
33 | 			this->Cells[idx] = Vector2D { cell.Get().X * Unsorted::LeptonsPerCell, cell.Get().Y * Unsorted::LeptonsPerCell };
34 | 		}
35 | 	}
36 | 
37 | 	this->Display.Read(exINI, pSection, "TiberiumEater.Display");
38 | 	this->DisplayToHouse.Read(exINI, pSection, "TiberiumEater.DisplayToHouse");
39 | 	this->DisplayOffset.Read(exINI, pSection, "TiberiumEater.DisplayOffset");
40 | 	this->Anims.Read(exINI, pSection, "TiberiumEater.Anims");
41 | 
42 | 	for (size_t idx = 0; idx < 4; ++idx)
43 | 	{
44 | 		_snprintf_s(tempBuffer, sizeof(tempBuffer), "TiberiumEater.Anims.Tiberium%d", idx);
45 | 		this->Anims_Tiberiums[idx].Read(exINI, pSection, tempBuffer);
46 | 	}
47 | 
48 | 	this->AnimMove.Read(exINI, pSection, "TiberiumEater.AnimMove");
49 | }
50 | 
51 | template 
52 | bool TiberiumEaterTypeClass::Serialize(T& stm)
53 | {
54 | 	return stm
55 | 		.Process(this->TransDelay)
56 | 		.Process(this->CashMultiplier)
57 | 		.Process(this->AmountPerCell)
58 | 		.Process(this->Cells)
59 | 		.Process(this->Display)
60 | 		.Process(this->DisplayToHouse)
61 | 		.Process(this->DisplayOffset)
62 | 		.Process(this->Anims)
63 | 		.Process(this->Anims_Tiberiums)
64 | 		.Process(this->AnimMove)
65 | 		.Success();
66 | }
67 | 
68 | #pragma region(save/load)
69 | 
70 | bool TiberiumEaterTypeClass::Load(PhobosStreamReader& stm, bool registerForChange)
71 | {
72 | 	return this->Serialize(stm);
73 | }
74 | 
75 | bool TiberiumEaterTypeClass::Save(PhobosStreamWriter& stm) const
76 | {
77 | 	return const_cast(this)->Serialize(stm);
78 | }
79 | 
80 | #pragma endregion
81 | 


--------------------------------------------------------------------------------
/src/New/Type/Affiliated/TiberiumEaterTypeClass.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | 
 3 | #include 
 4 | #include 
 5 | #include 
 6 | 
 7 | class TiberiumEaterTypeClass
 8 | {
 9 | public:
10 | 	Valueable TransDelay { -1 };
11 | 	Valueable  CashMultiplier { 1.0 };
12 | 	Valueable AmountPerCell { 0 };
13 | 	std::vector> Cells { std::vector>(1) };
14 | 	Valueable Display { true };
15 | 	Valueable DisplayToHouse { AffectedHouse::All };
16 | 	Valueable DisplayOffset { Point2D::Empty };
17 | 	ValueableVector Anims {};
18 | 	NullableVector Anims_Tiberiums[4] {};
19 | 	Valueable AnimMove { true };
20 | 
21 | 	TiberiumEaterTypeClass() = default;
22 | 
23 | 	void LoadFromINI(CCINIClass* pINI, const char* pSection);
24 | 	bool Load(PhobosStreamReader& stm, bool registerForChange);
25 | 	bool Save(PhobosStreamWriter& stm) const;
26 | 
27 | private:
28 | 
29 | 	template 
30 | 	bool Serialize(T& stm);
31 | };
32 | 


--------------------------------------------------------------------------------
/src/New/Type/Affiliated/TypeConvertGroup.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | 
 3 | #include 
 4 | 
 5 | class TypeConvertGroup
 6 | {
 7 | public:
 8 | 	ValueableVector FromTypes;
 9 | 	Nullable ToType;
10 | 	Nullable AppliedTo;
11 | 
12 | 	bool Load(PhobosStreamReader& stm, bool registerForChange);
13 | 	bool Save(PhobosStreamWriter& stm) const;
14 | 
15 | 	static void Parse(std::vector& list, INI_EX& exINI, const char* section, AffectedHouse defaultAffectHouse);
16 | 
17 | 	static void Convert(FootClass* pTargetFoot, const std::vector& convertPairs, HouseClass* pOwner);
18 | 
19 | private:
20 | 	template 
21 | 	bool Serialize(T& stm);
22 | };
23 | 


--------------------------------------------------------------------------------
/src/New/Type/DigitalDisplayTypeClass.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | #include 
 3 | #include 
 4 | #include 
 5 | #include 
 6 | #include 
 7 | 
 8 | class DigitalDisplayTypeClass final : public Enumerable
 9 | {
10 | public:
11 | 	Damageable Text_Color;
12 | 	Valueable Text_Background;
13 | 	Valueable> Offset;
14 | 	Nullable> Offset_ShieldDelta;
15 | 	Valueable Align;
16 | 	Anchor AnchorType;
17 | 	Valueable AnchorType_Building;
18 | 	Valueable Shape;
19 | 	CustomPalette Palette;
20 | 	Nullable> Shape_Spacing;
21 | 	Valueable Percentage;
22 | 	Nullable HideMaxValue;
23 | 	Valueable VisibleToHouses_Observer;
24 | 	Valueable VisibleToHouses;
25 | 	Valueable InfoType;
26 | 	Valueable ValueScaleDivisor;
27 | 
28 | 	DigitalDisplayTypeClass(const char* pTitle = NONE_STR) : Enumerable(pTitle)
29 | 		, Text_Color({ 0, 255, 0 }, { 255,255,0 }, { 255,0,0 })
30 | 		, Text_Background(false)
31 | 		, Offset({ 0, 0 })
32 | 		, Offset_ShieldDelta()
33 | 		, Align(TextAlign::Right)
34 | 		, AnchorType(HorizontalPosition::Right, VerticalPosition::Top)
35 | 		, AnchorType_Building(BuildingSelectBracketPosition::Top)
36 | 		, Shape(nullptr)
37 | 		, Palette()
38 | 		, Shape_Spacing()
39 | 		, Percentage(false)
40 | 		, HideMaxValue()
41 | 		, VisibleToHouses_Observer(true)
42 | 		, VisibleToHouses(AffectedHouse::All)
43 | 		, InfoType(DisplayInfoType::Health)
44 | 		, ValueScaleDivisor { 1 }
45 | 	{ }
46 | 
47 | 	void LoadFromINI(CCINIClass* pINI);
48 | 	void LoadFromStream(PhobosStreamReader& Stm);
49 | 	void SaveToStream(PhobosStreamWriter& Stm);
50 | 
51 | 	void Draw(Point2D position, int length, int value, int maxValue, bool isBuilding, bool isInfantry, bool hasShield);
52 | 
53 | private:
54 | 
55 | 	void DisplayText(Point2D& position, int length, int value, int maxValue, bool isBuilding, bool isInfantry, bool hasShield);
56 | 	void DisplayShape(Point2D& position, int length, int value, int maxValue, bool isBuilding, bool isInfantry, bool hasShield);
57 | 
58 | 	template 
59 | 	void Serialize(T& Stm);
60 | };
61 | 


--------------------------------------------------------------------------------
/src/New/Type/InsigniaTypeClass.cpp:
--------------------------------------------------------------------------------
 1 | #include "InsigniaTypeClass.h"
 2 | 
 3 | template<>
 4 | const char* Enumerable::GetMainSection()
 5 | {
 6 | 	return "InsigniaTypes";
 7 | }
 8 | 
 9 | void InsigniaTypeClass::LoadFromINI(CCINIClass* pINI)
10 | {
11 | 	const char* section = this->Name;
12 | 
13 | 	INI_EX exINI(pINI);
14 | 
15 | 	this->Insignia.Read(exINI, section, "Insignia.%s");
16 | 	this->InsigniaFrame.Read(exINI, section, "InsigniaFrame.%s");
17 | }
18 | 


--------------------------------------------------------------------------------
/src/New/Type/InsigniaTypeClass.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | 
 3 | #include 
 4 | #include 
 5 | 
 6 | class InsigniaTypeClass final : public Enumerable
 7 | {
 8 | public:
 9 | 	Promotable Insignia;
10 | 	Promotable InsigniaFrame;
11 | 
12 | 	InsigniaTypeClass(const char* const pTitle) : Enumerable(pTitle)
13 | 		, Insignia { }
14 | 		, InsigniaFrame { -1 }
15 | 	{ }
16 | 
17 | 	void LoadFromINI(CCINIClass* pINI);
18 | 	// No need to save and load as it's only for parsing
19 | };
20 | 


--------------------------------------------------------------------------------
/src/New/Type/LaserTrailTypeClass.cpp:
--------------------------------------------------------------------------------
 1 | #include "LaserTrailTypeClass.h"
 2 | 
 3 | #include 
 4 | #include 
 5 | 
 6 | template<>
 7 | const char* Enumerable::GetMainSection()
 8 | {
 9 | 	return "LaserTrailTypes";
10 | }
11 | 
12 | void LaserTrailTypeClass::LoadFromINI(CCINIClass* pINI)
13 | {
14 | 	const char* section = this->Name;
15 | 
16 | 	INI_EX exINI(pINI);
17 | 
18 | 	this->IsHouseColor.Read(exINI, section, "IsHouseColor");
19 | 	this->Color.Read(exINI, section, "Color");
20 | 
21 | 	this->FadeDuration.Read(exINI, section, "FadeDuration");
22 | 	this->Thickness.Read(exINI, section, "Thickness");
23 | 	this->SegmentLength.Read(exINI, section, "SegmentLength");
24 | 	this->IgnoreVertical.Read(exINI, section, "IgnoreVertical");
25 | 	this->IsIntense.Read(exINI, section, "IsIntense");
26 | 	this->CloakVisible.Read(exINI, section, "CloakVisible");
27 | 	this->CloakVisible_DetectedOnly.Read(exINI, section, "CloakVisible.DetectedOnly");
28 | 	this->DroppodOnly.Read(exINI, section, "DropPodOnly");
29 | }
30 | 
31 | template 
32 | void LaserTrailTypeClass::Serialize(T& Stm)
33 | {
34 | 	Stm
35 | 		.Process(this->IsHouseColor)
36 | 		.Process(this->Color)
37 | 		.Process(this->FadeDuration)
38 | 		.Process(this->Thickness)
39 | 		.Process(this->SegmentLength)
40 | 		.Process(this->IgnoreVertical)
41 | 		.Process(this->IsIntense)
42 | 		.Process(this->CloakVisible)
43 | 		.Process(this->CloakVisible_DetectedOnly)
44 | 		.Process(this->DroppodOnly)
45 | 		;
46 | }
47 | 
48 | void LaserTrailTypeClass::LoadFromStream(PhobosStreamReader& Stm)
49 | {
50 | 	this->Serialize(Stm);
51 | }
52 | 
53 | void LaserTrailTypeClass::SaveToStream(PhobosStreamWriter& Stm)
54 | {
55 | 	this->Serialize(Stm);
56 | }
57 | 


--------------------------------------------------------------------------------
/src/New/Type/LaserTrailTypeClass.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | 
 3 | #include 
 4 | #include 
 5 | 
 6 | class LaserTrailTypeClass final : public Enumerable
 7 | {
 8 | public:
 9 | 	Valueable IsHouseColor;
10 | 	Valueable Color;
11 | 	Valueable FadeDuration;
12 | 	Valueable Thickness;
13 | 	Valueable SegmentLength;
14 | 	Valueable IgnoreVertical;
15 | 	Valueable IsIntense;
16 | 	Valueable CloakVisible;
17 | 	Valueable CloakVisible_DetectedOnly;
18 | 	Valueable DroppodOnly;
19 | 
20 | 	LaserTrailTypeClass(const char* pTitle = NONE_STR) : Enumerable(pTitle)
21 | 		, IsHouseColor { false }
22 | 		, Color { { 255, 0, 0 } }
23 | 		, FadeDuration { 64 }
24 | 		, Thickness { 4 }
25 | 		, SegmentLength { 128 }
26 | 		, IgnoreVertical { false }
27 | 		, IsIntense { false }
28 | 		, CloakVisible { false }
29 | 		, CloakVisible_DetectedOnly { false }
30 | 		, DroppodOnly { false }
31 | 	{ }
32 | 
33 | 	void LoadFromINI(CCINIClass* pINI);
34 | 	void LoadFromStream(PhobosStreamReader& Stm);
35 | 	void SaveToStream(PhobosStreamWriter& Stm);
36 | 
37 | private:
38 | 	template 
39 | 	void Serialize(T& Stm);
40 | };
41 | 


--------------------------------------------------------------------------------
/src/New/Type/RadTypeClass.cpp:
--------------------------------------------------------------------------------
 1 | #include "RadTypeClass.h"
 2 | 
 3 | #include 
 4 | #include 
 5 | 
 6 | template<>
 7 | const char* Enumerable::GetMainSection()
 8 | {
 9 | 	return "RadiationTypes";
10 | }
11 | 
12 | void RadTypeClass::AddDefaults()
13 | {
14 | 	FindOrAllocate(GameStrings::Radiation);
15 | }
16 | 
17 | void RadTypeClass::LoadFromINI(CCINIClass* pINI)
18 | {
19 | 	const char* section = this->Name;
20 | 
21 | 	INI_EX exINI(pINI);
22 | 
23 | 	this->DurationMultiple.Read(exINI, section, "RadDurationMultiple");
24 | 	this->ApplicationDelay.Read(exINI, section, "RadApplicationDelay");
25 | 	this->ApplicationDelay_Building.Read(exINI, section, "RadApplicationDelay.Building");
26 | 	this->BuildingDamageMaxCount.Read(exINI, section, "RadBuildingDamageMaxCount");
27 | 	this->LevelMax.Read(exINI, section, "RadLevelMax");
28 | 	this->LevelDelay.Read(exINI, section, "RadLevelDelay");
29 | 	this->LightDelay.Read(exINI, section, "RadLightDelay");
30 | 	this->LevelFactor.Read(exINI, section, "RadLevelFactor");
31 | 	this->LightFactor.Read(exINI, section, "RadLightFactor");
32 | 	this->TintFactor.Read(exINI, section, "RadTintFactor");
33 | 	this->Color.Read(exINI, section, "RadColor");
34 | 	this->SiteWarhead.Read(exINI, section, "RadSiteWarhead");
35 | 	this->SiteWarhead_Detonate.Read(exINI, section, "RadSiteWarhead.Detonate");
36 | 	this->SiteWarhead_Detonate_Full.Read(exINI, section, "RadSiteWarhead.Detonate.Full");
37 | 	this->HasOwner.Read(exINI, section, "RadHasOwner");
38 | 	this->HasInvoker.Read(exINI, section, "RadHasInvoker");
39 | 
40 | 	if (this->GetBuildingApplicationDelay())
41 | 		Phobos::Optimizations::DisableRadDamageOnBuildings = false;
42 | }
43 | 
44 | template 
45 | void RadTypeClass::Serialize(T& Stm)
46 | {
47 | 	Stm
48 | 		.Process(this->DurationMultiple)
49 | 		.Process(this->ApplicationDelay)
50 | 		.Process(this->ApplicationDelay_Building)
51 | 		.Process(this->BuildingDamageMaxCount)
52 | 		.Process(this->LevelMax)
53 | 		.Process(this->LevelDelay)
54 | 		.Process(this->LightDelay)
55 | 		.Process(this->LevelFactor)
56 | 		.Process(this->LightFactor)
57 | 		.Process(this->TintFactor)
58 | 		.Process(this->Color)
59 | 		.Process(this->SiteWarhead)
60 | 		.Process(this->SiteWarhead_Detonate)
61 | 		.Process(this->SiteWarhead_Detonate_Full)
62 | 		.Process(this->HasOwner)
63 | 		.Process(this->HasInvoker)
64 | 		;
65 | };
66 | 
67 | void RadTypeClass::LoadFromStream(PhobosStreamReader& Stm)
68 | {
69 | 	this->Serialize(Stm);
70 | 
71 | 	if (this->GetBuildingApplicationDelay())
72 | 		Phobos::Optimizations::DisableRadDamageOnBuildings = false;
73 | }
74 | 
75 | void RadTypeClass::SaveToStream(PhobosStreamWriter& Stm)
76 | {
77 | 	this->Serialize(Stm);
78 | }
79 | 


--------------------------------------------------------------------------------
/src/New/Type/SelectBoxTypeClass.cpp:
--------------------------------------------------------------------------------
 1 | #include "SelectBoxTypeClass.h"
 2 | 
 3 | template<>
 4 | const char* Enumerable::GetMainSection()
 5 | {
 6 | 	return "SelectBoxTypes";
 7 | }
 8 | 
 9 | void SelectBoxTypeClass::LoadFromINI(CCINIClass* pINI)
10 | {
11 | 	const char* pSection = this->Name;
12 | 	if (!_stricmp(pSection, NONE_STR))
13 | 		return;
14 | 
15 | 	INI_EX exINI(pINI);
16 | 
17 | 	this->Shape.Read(exINI, pSection, "Shape");
18 | 	this->Palette.LoadFromINI(pINI, pSection, "Palette");
19 | 	this->Frames.Read(exINI, pSection, "Frames");
20 | 	this->Grounded.Read(exINI, pSection, "Grounded");
21 | 	this->Offset.Read(exINI, pSection, "Offset");
22 | 	this->Translucency.Read(exINI, pSection, "Translucency");
23 | 	this->VisibleToHouses.Read(exINI, pSection, "VisibleToHouses");
24 | 	this->VisibleToHouses_Observer.Read(exINI, pSection, "VisibleToHouses.Observer");
25 | 	this->DrawAboveTechno.Read(exINI, pSection, "DrawAboveTechno");
26 | }
27 | 
28 | template 
29 | void SelectBoxTypeClass::Serialize(T& Stm)
30 | {
31 | 	Stm
32 | 		.Process(this->Shape)
33 | 		.Process(this->Palette)
34 | 		.Process(this->Frames)
35 | 		.Process(this->Grounded)
36 | 		.Process(this->Offset)
37 | 		.Process(this->Translucency)
38 | 		.Process(this->VisibleToHouses)
39 | 		.Process(this->VisibleToHouses_Observer)
40 | 		.Process(this->DrawAboveTechno)
41 | 		;
42 | }
43 | 
44 | void SelectBoxTypeClass::LoadFromStream(PhobosStreamReader& Stm)
45 | {
46 | 	this->Serialize(Stm);
47 | }
48 | 
49 | void SelectBoxTypeClass::SaveToStream(PhobosStreamWriter& Stm)
50 | {
51 | 	this->Serialize(Stm);
52 | }
53 | 


--------------------------------------------------------------------------------
/src/New/Type/SelectBoxTypeClass.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | 
 3 | #include 
 4 | #include 
 5 | #include 
 6 | 
 7 | class SelectBoxTypeClass final : public Enumerable
 8 | {
 9 | public:
10 | 	Valueable Shape;
11 | 	CustomPalette Palette;
12 | 	Nullable> Frames;
13 | 	Valueable Grounded;
14 | 	Valueable Offset;
15 | 	TranslucencyLevel Translucency;
16 | 	Valueable VisibleToHouses;
17 | 	Valueable VisibleToHouses_Observer;
18 | 	Valueable DrawAboveTechno;
19 | 
20 | 	SelectBoxTypeClass(const char* pTitle = NONE_STR) : Enumerable(pTitle)
21 | 		, Shape { FileSystem::LoadSHPFile("select.shp") }
22 | 		, Palette {}
23 | 		, Frames {}
24 | 		, Grounded { false }
25 | 		, Offset { Point2D::Empty }
26 | 		, Translucency { 0 }
27 | 		, VisibleToHouses { AffectedHouse::All }
28 | 		, VisibleToHouses_Observer { true }
29 | 		, DrawAboveTechno { true }
30 | 	{ }
31 | 
32 | 	void LoadFromINI(CCINIClass* pINI);
33 | 	void LoadFromStream(PhobosStreamReader& Stm);
34 | 	void SaveToStream(PhobosStreamWriter& Stm);
35 | 
36 | private:
37 | 	template 
38 | 	void Serialize(T& Stm);
39 | };
40 | 


--------------------------------------------------------------------------------
/src/Phobos.COM.cpp:
--------------------------------------------------------------------------------
 1 | #include "Phobos.COM.h"
 2 | 
 3 | #include 
 4 | 
 5 | #include 
 6 | 
 7 | 
 8 | #ifdef CUSTOM_LOCO_EXAMPLE_ENABLED // Register the loco
 9 | DEFINE_HOOK(0x6BD68D, WinMain_PhobosRegistrations, 0x6)
10 | {
11 | 	Debug::Log("Starting COM registration...\n");
12 | 
13 | 	// Add new classes to be COM-registered below
14 | 	RegisterFactoryForClass();
15 | 
16 | 	Debug::Log("COM registration done!\n");
17 | 
18 | 	return 0;
19 | }
20 | #endif
21 | 


--------------------------------------------------------------------------------
/src/Phobos.COM.h:
--------------------------------------------------------------------------------
 1 | #include 
 2 | #include 
 3 | 
 4 | // Registers a manually created factory for a class.
 5 | template
 6 | void RegisterFactoryForClass(IClassFactory* pFactory)
 7 | {
 8 | 	DWORD dwRegister = 0;
 9 | 	HRESULT hr = CoRegisterClassObject(__uuidof(T), pFactory, CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &dwRegister);
10 | 
11 | 	if (FAILED(hr))
12 | 		Debug::Log("CoRegisterClassObject for %s class factory failed with error code %d.\n", typeid(T).name(), GetLastError());
13 | 	else
14 | 		Debug::Log("Class factory for %s registered.\n", typeid(T).name());
15 | 
16 | 	Game::COMClasses->AddItem((ULONG)dwRegister);
17 | }
18 | 
19 | // Registers an automatically created factory for a class.
20 | template
21 | void RegisterFactoryForClass()
22 | {
23 | 	RegisterFactoryForClass(GameCreate>());
24 | }
25 | 


--------------------------------------------------------------------------------
/src/Phobos.CRT.cpp:
--------------------------------------------------------------------------------
 1 | #include 
 2 | 
 3 | #include 
 4 | 
 5 | void PhobosCRT::strCopy(char* Dest, const char* Source, size_t Count)
 6 | {
 7 | 	strncpy_s(Dest, Count, Source, Count - 1);
 8 | 	Dest[Count - 1] = 0;
 9 | }
10 | 
11 | void PhobosCRT::wstrCopy(wchar_t* Dest, const wchar_t* Source, size_t Count)
12 | {
13 | 	wcsncpy_s(Dest, Count, Source, Count - 1);
14 | 	Dest[Count - 1] = 0;
15 | }
16 | 


--------------------------------------------------------------------------------
/src/Phobos.CRT.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | 
 3 | class PhobosCRT
 4 | {
 5 | public:
 6 | 
 7 | 	// these two are saner mechanisms for string copying
 8 | 
 9 | 	// copy up to Count chars using strncpy
10 | 	// force (Count - 1)th char to \0
11 | 	// which means you pass the full length of the char[]/wchar_t[] as Count and it will not overflow
12 | 	// it doesn't mean you can copy strings without thinking
13 | 	static void strCopy(char* Dest, const char* Source, size_t Count);
14 | 	static void wstrCopy(wchar_t* Dest, const wchar_t* Source, size_t Count);
15 | 
16 | 	template
17 | 	static void strCopy(char(&Dest)[Size], const char* Source)
18 | 	{
19 | 		strCopy(Dest, Source, Size);
20 | 	}
21 | 
22 | 	template
23 | 	static void wstrCopy(wchar_t(&Dest)[Size], const wchar_t* Source)
24 | 	{
25 | 		wstrCopy(Dest, Source, Size);
26 | 	}
27 | };
28 | 


--------------------------------------------------------------------------------
/src/Phobos.version.h:
--------------------------------------------------------------------------------
 1 | #ifndef VERSION_H
 2 | #define VERSION_H
 3 | 
 4 | #define _WSTR(x) _WSTR_(x)
 5 | #define _WSTR_(x) L ## #x
 6 | #define _STR(x) _STR_(x)
 7 | #define _STR_(x) #x
 8 | 
 9 | #pragma region Release build version numbering
10 | 
11 | // Indicates project maturity and completeness
12 | #define VERSION_MAJOR 0
13 | 
14 | // Indicates major changes and significant additions, like new logics
15 | #define VERSION_MINOR 3
16 | 
17 | // Indicates minor changes, like vanilla bugfixes, unhardcodings or hacks
18 | #define VERSION_REVISION 0
19 | 
20 | // Indicates Phobos-related bugfixes only
21 | #define VERSION_PATCH 1
22 | 
23 | #pragma endregion
24 | 
25 | // Build number. Incremented on each released build.
26 | #define BUILD_NUMBER 47
27 | 
28 | // Nightly defines GIT_COMMIT and GIT_BRANCH in GH Actions
29 | 
30 | #ifdef IS_RELEASE_VER // Release build metadata
31 | 	#define SAVEGAME_ID ((VERSION_MAJOR << 24) | (VERSION_MINOR << 16) | (VERSION_REVISION << 8) | VERSION_PATCH)
32 | 	#define FILE_DESCRIPTION "Phobos, Ares-compatible YR engine extension"
33 | 	#define FILE_VERSION_STR _STR(VERSION_MAJOR) "." _STR(VERSION_MINOR) "." _STR(VERSION_REVISION) "." _STR(VERSION_PATCH)
34 | 	#define FILE_VERSION VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, VERSION_PATCH
35 | 	#define PRODUCT_VERSION "Release Build " FILE_VERSION_STR
36 | #elif defined(GIT_COMMIT) // Nightly devbuild metadata
37 | 	#define STR_GIT_COMMIT _STR(GIT_COMMIT)
38 | 	#define STR_GIT_BRANCH _STR(GIT_BRANCH)
39 | 
40 | 	#define SAVEGAME_ID ((BUILD_NUMBER << 24) | (BUILD_NUMBER << 12) | (BUILD_NUMBER))
41 | 	#define FILE_DESCRIPTION "Unstable nightly devbuild of Phobos engine extension"
42 | 	#define FILE_VERSION_STR "Commit " STR_GIT_COMMIT
43 | 	#define FILE_VERSION 0
44 | 	#define PRODUCT_VERSION "Nightly Build " STR_GIT_COMMIT " @ " STR_GIT_BRANCH
45 | #else // Regular devbuild metadata
46 | 	#define SAVEGAME_ID ((BUILD_NUMBER << 24) | (BUILD_NUMBER << 12) | (BUILD_NUMBER))
47 | 	#define FILE_DESCRIPTION "Development build of Phobos engine extension"
48 | 	#define FILE_VERSION_STR "Build #" _STR(BUILD_NUMBER)
49 | 	#define FILE_VERSION 0,0,0,BUILD_NUMBER
50 | 	#define PRODUCT_VERSION "Development Build #" _STR(BUILD_NUMBER)
51 | #endif
52 | 
53 | #endif // VERSION_H
54 | 


--------------------------------------------------------------------------------
/src/Utilities/Anchor.cpp:
--------------------------------------------------------------------------------
 1 | #include "Anchor.h"
 2 | 
 3 | #include 
 4 | 
 5 | double Anchor::GetRelativeOffsetHorizontal() const
 6 | {
 7 | 	// Enum goes from 0 to 2 from left to right. Cast it and divide it
 8 | 	// by 2 and you get the percentage. Pretty clever huh? - Kerbiter
 9 | 	return (static_cast(this->Horizontal.Get()) / 2.0);
10 | }
11 | 
12 | double Anchor::GetRelativeOffsetVertical() const
13 | {
14 | 	// Same deal as with the left-right one - Kerbiter
15 | 	return (static_cast(this->Vertical.Get()) / 2.0);
16 | }
17 | 
18 | Point2D Anchor::OffsetPosition(
19 | 	const Point2D& topLeft,
20 | 	const Point2D& topRight,
21 | 	const Point2D& bottomLeft) const
22 | {
23 | 	Point2D result { topLeft };
24 | 	Point2D deltaTopRight { topRight - topLeft };
25 | 	Point2D deltaBottomLeft { bottomLeft - topLeft };
26 | 
27 | 	result += deltaTopRight * this->GetRelativeOffsetHorizontal();
28 | 	result += deltaBottomLeft * this->GetRelativeOffsetVertical();
29 | 
30 | 	return result;
31 | }
32 | 
33 | Point2D Anchor::OffsetPosition(const RectangleStruct& rect) const
34 | {
35 | 	Point2D result { rect.X, rect.Y };
36 | 
37 | 	result.X += static_cast(rect.Width * this->GetRelativeOffsetHorizontal());
38 | 	result.Y += static_cast(rect.Height * this->GetRelativeOffsetVertical());
39 | 
40 | 	return result;
41 | }
42 | 
43 | Point2D Anchor::OffsetPosition(const LTRBStruct& ltrb) const
44 | {
45 | 	Point2D result { ltrb.Left, ltrb.Top };
46 | 	int deltaX = ltrb.Right - ltrb.Left;
47 | 	int deltaY = ltrb.Bottom - ltrb.Top;
48 | 
49 | 	result.X += static_cast(deltaX * this->GetRelativeOffsetHorizontal());
50 | 	result.Y += static_cast(deltaY * this->GetRelativeOffsetVertical());
51 | 
52 | 	return result;
53 | }
54 | 
55 | void Anchor::Read(INI_EX& parser, const char* pSection, const char* pFlagFormat)
56 | {
57 | 	char flagName[0x40];
58 | 
59 | 	_snprintf_s(flagName, _TRUNCATE, pFlagFormat, "Horizontal");
60 | 	this->Horizontal.Read(parser, pSection, flagName);
61 | 
62 | 	_snprintf_s(flagName, _TRUNCATE, pFlagFormat, "Vertical");
63 | 	this->Vertical.Read(parser, pSection, flagName);
64 | }
65 | 
66 | bool Anchor::Load(PhobosStreamReader& stm, bool registerForChange)
67 | {
68 | 	return this->Serialize(stm);
69 | }
70 | 
71 | bool Anchor::Save(PhobosStreamWriter& stm) const
72 | {
73 | 	return const_cast(this)->Serialize(stm);
74 | }
75 | 
76 | template 
77 | bool Anchor::Serialize(T& stm)
78 | {
79 | 	return stm
80 | 		.Process(this->Horizontal)
81 | 		.Process(this->Vertical)
82 | 		.Success();
83 | }
84 | 


--------------------------------------------------------------------------------
/src/Utilities/Anchor.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | #include 
 3 | #include 
 4 | 
 5 | #include 
 6 | 
 7 | // Helper class to get anchor points on an arbitrary rectangle or a parallelogram
 8 | class Anchor
 9 | {
10 | public:
11 | 	Valueable Horizontal { HorizontalPosition::Left };
12 | 	Valueable   Vertical { VerticalPosition::Top };
13 | 
14 | 	Anchor(HorizontalPosition hPos, VerticalPosition vPos)
15 | 		: Horizontal { hPos }, Vertical { vPos }
16 | 	{ }
17 | 
18 | 	// Maps enum values to offset relative to width
19 | 	double GetRelativeOffsetHorizontal() const;
20 | 	// Maps enum values to offset relative to height
21 | 	double GetRelativeOffsetVertical() const;
22 | 
23 | 	// Get an anchor point for a freeform parallelogram
24 | 	Point2D OffsetPosition(
25 | 		const Point2D& topLeft,
26 | 		const Point2D& topRight,
27 | 		const Point2D& bottomLeft
28 | 	) const;
29 | 
30 | 	Point2D OffsetPosition(const RectangleStruct& rect) const;
31 | 	Point2D OffsetPosition(const LTRBStruct& ltrb) const;
32 | 
33 | 	void Read(INI_EX& parser, const char* pSection, const char* pBaseFlag);
34 | 	bool Load(PhobosStreamReader& Stm, bool RegisterForChange);
35 | 	bool Save(PhobosStreamWriter& Stm) const;
36 | 
37 | private:
38 | 	template 
39 | 	bool Serialize(T& stm);
40 | };
41 | 


--------------------------------------------------------------------------------
/src/Utilities/AresFunctions.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | #include 
 3 | #include "Constructs.h"
 4 |  
 5 | class TechnoClass;
 6 | class TechnoTypeClass;
 7 | class EBolt;
 8 | class FootClass;
 9 | class HouseClass;
10 | class BuildingTypeClass;
11 | class BuildingClass;
12 | class HouseTypeClass;
13 | class SuperClass;
14 | class SuperWeaponTypeClass;
15 | class AlphaShapeClass;
16 | 
17 | class AresTechnoExtData;
18 | class AresTechnoTypeExtData;
19 | class AresHouseExtData;
20 | class AresSWTypeExtData;
21 | 
22 | class AresFunctions
23 | {
24 | public:
25 | 	static void InitAres3_0();
26 | 	static void InitAres3_0p1();
27 | 	static void InitNoAres();
28 | 	// TechnoExt
29 | 	static bool(__stdcall* ConvertTypeTo)(TechnoClass* pFoot, TechnoTypeClass* pConvertTo);
30 | 
31 | 	static EBolt* (__stdcall* CreateAresEBolt)(WeaponTypeClass* pWeapon);
32 | 
33 | 	static void(__stdcall* SpawnSurvivors)(FootClass* pThis, TechnoClass* pKiller, bool Select, bool IgnoreDefenses);
34 | 
35 | 	static bool(__thiscall* IsTargetConstraintsEligible)(void*, HouseClass*, bool);
36 | 
37 | 	static std::function SWTypeExtMap_Find;
38 | 
39 | 	static PhobosMap* AlphaExtMap;
40 | private:
41 | 
42 | 	static constexpr bool _maybe = false;
43 | 
44 | 	static constexpr bool AresWasWrongAboutSpawnSurvivors = _maybe;
45 | 
46 | 	static void* _SWTypeExtMap;
47 | 	static AresSWTypeExtData* (__thiscall* _SWTypeExtMapFind)(void*, SuperWeaponTypeClass*);
48 | };
49 | 


--------------------------------------------------------------------------------
/src/Utilities/AresHelper.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | #include 
 3 | #include 
 4 | #include 
 5 | #include 
 6 | 
 7 | class AresHelper
 8 | {
 9 | public:
10 | 	enum class Version
11 | 	{
12 | 		Unknown = -1,
13 | 		Ares30 = 0,
14 | 		Ares30p,
15 | 	};
16 | 
17 | private:
18 | 	typedef std::unordered_map AresTimestampMap;
19 | 
20 | 	// timestamp bytes for each version
21 | 	static const AresTimestampMap AresTimestampBytes;
22 | 
23 | 	static void GetGameModulesBaseAddresses();
24 | 
25 | public:
26 | 	static HMODULE AresDllHmodule;
27 | 	static uintptr_t AresBaseAddress;
28 | 	static uintptr_t PhobosBaseAddress;
29 | 
30 | 	// numeric id of currently used version, zero-indexed, -1 is unknown or missing
31 | 	static Version AresVersion;
32 | 	// is Ares detected and version known?
33 | 	static bool CanUseAres;
34 | 
35 | 	static void Init();
36 | };
37 | 


--------------------------------------------------------------------------------
/src/Utilities/Coroutine.h:
--------------------------------------------------------------------------------
  1 | #pragma once
  2 | 
  3 | // This header contains simple wraps for C++20 coroutine
  4 | // Before C++23 we probably needs it
  5 | // Author: secsome
  6 | 
  7 | #include 
  8 | #include 
  9 | 
 10 | // The simplest coroutine which return an optional value
 11 | // Can be used as a state machine
 12 | template
 13 | struct Generator
 14 | {
 15 | 	struct promise_type;
 16 | 
 17 | 	Generator(const Generator&) = delete;
 18 | 	Generator& operator=(const Generator&) = delete;
 19 | 
 20 | 	~Generator()
 21 | 	{
 22 | 		if (handle_)
 23 | 			handle_.destroy();
 24 | 	}
 25 | 
 26 | 	struct promise_type
 27 | 	{
 28 | 		T value;
 29 | 
 30 | 		auto get_return_object()
 31 | 		{
 32 | 			return Generator(std::coroutine_handle::from_promise(*this));
 33 | 		}
 34 | 
 35 | 		auto initial_suspend()
 36 | 		{
 37 | 			return std::suspend_always();
 38 | 		}
 39 | 
 40 | 		auto final_suspend()
 41 | 		{
 42 | 			return std::suspend_always();
 43 | 		}
 44 | 
 45 | 		void return_void() { }
 46 | 
 47 | 		auto yield_value(T v)
 48 | 		{
 49 | 			value = v;
 50 | 			return std::suspend_always();
 51 | 		}
 52 | 
 53 | 		void unhandled_exception()
 54 | 		{
 55 | 			// std::terminate();
 56 | 		}
 57 | 	};
 58 | 
 59 | 	std::optional next()
 60 | 	{
 61 | 		std::optional ret;
 62 | 
 63 | 		if (handle_)
 64 | 		{
 65 | 			handle_.resume();
 66 | 			if (!handle_.done())
 67 | 				ret.emplace(handle_.promise().value);
 68 | 		}
 69 | 
 70 | 		return ret;
 71 | 	}
 72 | 
 73 | private:
 74 | 	std::coroutine_handle handle_;
 75 | };
 76 | 
 77 | #if 0
 78 | // Sample: Fibonacci sequence: 1, 1, 2, 3, 5, 8, 13, ...
 79 | // For this show case we just let it only have the first 12 elements
 80 | Generator Fibonacci()
 81 | {
 82 | 	co_yield 1;
 83 | 	co_yield 1;
 84 | 	int a = 1, b = 1;
 85 | 
 86 | 	int cnt = 10;
 87 | 	while (cnt--)
 88 | 	{
 89 | 		int c = a + b;
 90 | 		a = b;
 91 | 		b = c;
 92 | 		co_yield c;
 93 | 	}
 94 | }
 95 | 
 96 | void Test_Fibonacci()
 97 | {
 98 | 	auto f = Fibonacci();
 99 | 	while (true)
100 | 	{
101 | 		auto t = f.next();
102 | 		if (!t.has_value())
103 | 			break;
104 | 		printf("%d, ", t.value());
105 | 	}
106 | 	printf("\n");
107 | }
108 | #endif
109 | 


--------------------------------------------------------------------------------
/src/Utilities/EnumFunctions.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | 
 3 | #include 
 4 | #include 
 5 | 
 6 | #include "Enum.h"
 7 | 
 8 | class EnumFunctions
 9 | {
10 | public:
11 | 	static bool CanTargetHouse(AffectedHouse flags, HouseClass* ownerHouse, HouseClass* targetHouse);
12 | 	static bool IsCellEligible(CellClass* const pCell, AffectedTarget allowed, bool explicitEmptyCells = false, bool considerBridgesLand = false);
13 | 	static bool IsTechnoEligible(TechnoClass* const pTechno, AffectedTarget allowed, bool considerAircraftSeparately = false);
14 | 	static bool AreCellAndObjectsEligible(CellClass* const pCell, AffectedTarget allowed, AffectedHouse allowedHouses, HouseClass* owner, bool explicitEmptyCells = false, bool considerAircraftSeparately = false, bool allowBridges = false);
15 | };
16 | 


--------------------------------------------------------------------------------
/src/Utilities/GeneralUtils.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | #include 
 3 | #include 
 4 | #include 
 5 | 
 6 | #include 
 7 | #include 
 8 | #include 
 9 | 
10 | #include 
11 | #include 
12 | #include 
13 | #include 
14 | 
15 | #include "Template.h"
16 | 
17 | #define MIN(x) std::numeric_limits::min()
18 | #define MAX(x) std::numeric_limits::max()
19 | 
20 | class GeneralUtils
21 | {
22 | public:
23 | 	static bool IsValidString(const char* str);
24 | 	static void IntValidCheck(int* source, const char* section, const char* tag, int defaultValue, int min = MIN(int), int max = MAX(int));
25 | 	static void DoubleValidCheck(double* source, const char* section, const char* tag, double defaultValue, double min = MIN(double), double max = MAX(double));
26 | 	static const wchar_t* LoadStringOrDefault(const char* key, const wchar_t* defaultValue);
27 | 	static const wchar_t* LoadStringUnlessMissing(const char* key, const wchar_t* defaultValue);
28 | 	static std::vector AdjacentCellsInRange(unsigned int range);
29 | 	static const int GetRangedRandomOrSingleValue(PartialVector2D range);
30 | 	static const double GetRangedRandomOrSingleValue(PartialVector2D range);
31 | 	static const double GetWarheadVersusArmor(WarheadTypeClass* pWH, Armor armorType);
32 | 	static const double GetWarheadVersusArmor(WarheadTypeClass* pWH, TechnoClass* pThis, TechnoTypeClass* pType = nullptr);
33 | 	static int ChooseOneWeighted(const double dice, const std::vector* weights);
34 | 	static bool HasHealthRatioThresholdChanged(double oldRatio, double newRatio);
35 | 	static bool ApplyTheaterSuffixToString(char* str);
36 | 	static std::string IntToDigits(int num);
37 | 	static int CountDigitsInNumber(int number);
38 | 	static CoordStruct CalculateCoordsFromDistance(CoordStruct currentCoords, CoordStruct targetCoords, int distance);
39 | 	static void DisplayDamageNumberString(int damage, DamageDisplayType type, CoordStruct coords, int& offset);
40 | 	static int GetColorFromColorAdd(int colorIndex);
41 | 	static DynamicVectorClass* BuildPalette(const char* paletteFileName);
42 | 
43 | 	template
44 | 	static constexpr T FastPow(T x, size_t n)
45 | 	{
46 | 		// Real fast pow calc x^n in O(log(n))
47 | 		T result = 1;
48 | 		T base = x;
49 | 		while (n)
50 | 		{
51 | 			if (n & 1) result *= base;
52 | 			base *= base;
53 | 			n >>= 1;
54 | 		}
55 | 		return result;
56 | 	}
57 | };
58 | 


--------------------------------------------------------------------------------
/src/Utilities/Patch.cpp:
--------------------------------------------------------------------------------
 1 | #include "Patch.h"
 2 | #include "Macro.h"
 3 | #include 
 4 | 
 5 | int GetSection(const char* sectionName, void** pVirtualAddress)
 6 | {
 7 | 	auto hInstance = Phobos::hInstance;
 8 | 	auto pHeader = reinterpret_cast(((PIMAGE_DOS_HEADER)hInstance)->e_lfanew + (long)hInstance);
 9 | 
10 | 	for (int i = 0; i < pHeader->FileHeader.NumberOfSections; i++)
11 | 	{
12 | 		auto sct_hdr = IMAGE_FIRST_SECTION(pHeader) + i;
13 | 
14 | 		if (strncmp(sectionName, (char*)sct_hdr->Name, 8) == 0)
15 | 		{
16 | 			*pVirtualAddress = (void*)((DWORD)hInstance + sct_hdr->VirtualAddress);
17 | 			return sct_hdr->Misc.VirtualSize;
18 | 		}
19 | 	}
20 | 	return 0;
21 | }
22 | 
23 | void Patch::ApplyStatic()
24 | {
25 | 	void* buffer;
26 | 	const int len = GetSection(PATCH_SECTION_NAME, &buffer);
27 | 
28 | 	for (int offset = 0; offset < len; offset += sizeof(Patch))
29 | 	{
30 | 		const auto pPatch = (Patch*)((DWORD)buffer + offset);
31 | 		if (pPatch->offset == 0)
32 | 			return;
33 | 
34 | 		pPatch->Apply();
35 | 	}
36 | }
37 | 
38 | void Patch::Apply()
39 | {
40 | 	void* pAddress = (void*)this->offset;
41 | 
42 | 	DWORD protect_flag;
43 | 	VirtualProtect(pAddress, this->size, PAGE_EXECUTE_READWRITE, &protect_flag);
44 | 	memcpy(pAddress, this->pData, this->size);
45 | 	VirtualProtect(pAddress, this->size, protect_flag, &protect_flag);
46 | 	// NOTE: Instruction cache flush isn't required on x86. This is just to conform with Win32 API docs.
47 | 	FlushInstructionCache(GetCurrentProcess(), pAddress, this->size);
48 | }
49 | 
50 | void Patch::Apply_LJMP(DWORD offset, DWORD pointer)
51 | {
52 | 	const _LJMP data(offset, pointer);
53 | 	Patch patch = { offset, sizeof(data), (byte*)&data };
54 | 	patch.Apply();
55 | }
56 | 
57 | void Patch::Apply_CALL(DWORD offset, DWORD pointer)
58 | {
59 | 	const _CALL data(offset, pointer);
60 | 	Patch patch = { offset, sizeof(data), (byte*)&data };
61 | 	patch.Apply();
62 | }
63 | 
64 | void Patch::Apply_CALL6(DWORD offset, DWORD pointer)
65 | {
66 | 	const _CALL6 data(offset, pointer);
67 | 	Patch patch = { offset, sizeof(data), (byte*)&data };
68 | 	patch.Apply();
69 | }
70 | 


--------------------------------------------------------------------------------
/src/Utilities/Patch.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | #include 
 3 | #include 
 4 | 
 5 | // no more than 8 characters
 6 | #define PATCH_SECTION_NAME ".patch"
 7 | #pragma section(PATCH_SECTION_NAME, read)
 8 | 
 9 | #pragma pack(push, 1)
10 | #pragma warning(push)
11 | #pragma warning(disable : 4324)
12 | struct __declspec(novtable) Patch
13 | {
14 | 	DWORD offset;
15 | 	DWORD size;
16 | 	byte* pData;
17 | 
18 | 	void Apply();
19 | 
20 | 	// static
21 | 	static void ApplyStatic();
22 | 
23 | 	template 
24 | 	static void Apply_TYPED(DWORD offset, std::initializer_list data)
25 | 	{
26 | 		Patch patch = { offset, data.size() * sizeof(T), const_cast(reinterpret_cast(data.begin())) };
27 | 		patch.Apply();
28 | 	};
29 | 
30 | 	template 
31 | 	static inline void Apply_RAW(DWORD offset, const char(&str)[Size])
32 | 	{
33 | 		Patch patch = { offset, Size, (byte*)str };
34 | 		patch.Apply();
35 | 	};
36 | 
37 | 	static inline void Apply_RAW(DWORD offset, std::initializer_list data)
38 | 	{
39 | 		Apply_TYPED(offset, data);
40 | 	};
41 | 
42 | 	static void Apply_LJMP(DWORD offset, DWORD pointer);
43 | 	static inline void Apply_LJMP(DWORD offset, void* pointer)
44 | 	{
45 | 		Apply_LJMP(offset, reinterpret_cast(pointer));
46 | 	};
47 | 
48 | 	static void Apply_CALL(DWORD offset, DWORD pointer);
49 | 	static inline void Apply_CALL(DWORD offset, void* pointer)
50 | 	{
51 | 		Apply_CALL(offset, reinterpret_cast(pointer));
52 | 	};
53 | 
54 | 	static void Apply_CALL6(DWORD offset, DWORD pointer);
55 | 	static inline void Apply_CALL6(DWORD offset, void* pointer)
56 | 	{
57 | 		Apply_CALL6(offset, reinterpret_cast(pointer));
58 | 	};
59 | 
60 | 	static inline void Apply_VTABLE(DWORD offset, DWORD pointer)
61 | 	{
62 | 		Patch::Apply_TYPED(offset, { pointer });
63 | 	};
64 | 
65 | 	static inline void Apply_VTABLE(DWORD offset, void* pointer)
66 | 	{
67 | 		Apply_OFFSET(offset, reinterpret_cast(pointer));
68 | 	};
69 | 
70 | 	static inline void Apply_OFFSET(DWORD offset, DWORD pointer)
71 | 	{
72 | 		Apply_VTABLE(offset, pointer);
73 | 	};
74 | 
75 | 	static inline void Apply_OFFSET(DWORD offset, void* pointer)
76 | 	{
77 | 		Apply_VTABLE(offset, pointer);
78 | 	};
79 | };
80 | #pragma warning(pop)
81 | #pragma pack(pop)
82 | 


--------------------------------------------------------------------------------
/src/Utilities/Savegame.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | 
 3 | #include "Stream.h"
 4 | 
 5 | #include 
 6 | #include 
 7 | 
 8 | namespace Savegame
 9 | {
10 | 	template 
11 | 	bool ReadPhobosStream(PhobosStreamReader& Stm, T& Value, bool RegisterForChange = true);
12 | 
13 | 	template 
14 | 	bool WritePhobosStream(PhobosStreamWriter& Stm, const T& Value);
15 | 
16 | 	template 
17 | 	T* RestoreObject(PhobosStreamReader& Stm, bool RegisterForChange = true);
18 | 
19 | 	template 
20 | 	bool PersistObject(PhobosStreamWriter& Stm, const T* pValue);
21 | 
22 | 	template 
23 | 	struct PhobosStreamObject
24 | 	{
25 | 		bool ReadFromStream(PhobosStreamReader& Stm, T& Value, bool RegisterForChange) const;
26 | 		bool WriteToStream(PhobosStreamWriter& Stm, const T& Value) const;
27 | 	};
28 | 
29 | 	template 
30 | 	struct ObjectFactory
31 | 	{
32 | 		std::unique_ptr operator() (PhobosStreamReader& Stm) const
33 | 		{
34 | 			return std::make_unique();
35 | 		}
36 | 	};
37 | }
38 | 


--------------------------------------------------------------------------------
/src/Utilities/ShapeTextPrinter.cpp:
--------------------------------------------------------------------------------
 1 | #include "ShapeTextPrinter.h"
 2 | 
 3 | void ShapeTextPrinter::PrintShape
 4 | (
 5 | 	const char* text,
 6 | 	ShapeTextPrintData& data,
 7 | 	Point2D position,
 8 | 	RectangleStruct& bounds,
 9 | 	DSurface* pSurface,
10 | 	Point2D offset,
11 | 	BlitterFlags blitterFlags,
12 | 	int brightness,
13 | 	int tintColor
14 | )
15 | {
16 | 	const int length = strlen(text);
17 | 	std::vector frames;
18 | 
19 | 	for (int i = 0; i < length; i++)
20 | 	{
21 | 		int frame = 0;
22 | 
23 | 		if (isdigit(text[i]))
24 | 		{
25 | 			frame = data.BaseNumberFrame + text[i] - '0';
26 | 		}
27 | 		else
28 | 		{
29 | 			size_t signIndex = SignSequence.find(text[i]);
30 | 
31 | 			if (signIndex < SignSequence.size())
32 | 				frame = data.BaseExtraFrame + signIndex;
33 | 			else
34 | 				return;
35 | 		}
36 | 
37 | 		frames.emplace_back(frame);
38 | 	}
39 | 
40 | 	for (int frame : frames)
41 | 	{
42 | 		pSurface->DrawSHP
43 | 		(
44 | 			const_cast(data.Palette),
45 | 			const_cast(data.Shape),
46 | 			frame,
47 | 			&position,
48 | 			&bounds,
49 | 			BlitterFlags::None,
50 | 			0,
51 | 			0,
52 | 			ZGradient::Ground,
53 | 			brightness,
54 | 			tintColor,
55 | 			nullptr,
56 | 			0,
57 | 			0,
58 | 			0
59 | 		);
60 | 
61 | 		position.X += data.Spacing.X;
62 | 		position.Y -= data.Spacing.Y;
63 | 	}
64 | }
65 | 


--------------------------------------------------------------------------------
/src/Utilities/ShapeTextPrinter.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | #include 
 3 | 
 4 | // only numbers and sign
 5 | class ShapeTextPrintData
 6 | {
 7 | public:
 8 | 	// Shape
 9 | 	const SHPStruct* const Shape;
10 | 	const ConvertClass* const Palette;
11 | 	int BaseNumberFrame;	// frame index of 0
12 | 	int BaseExtraFrame;		// as sequence ShapeTextPrinter::SignSequence
13 | 	Vector2D Spacing;
14 | 
15 | 	ShapeTextPrintData(const SHPStruct* const shape, const ConvertClass* const palette, int baseNumberFrame, int baseExtraFrame, const Vector2D& spacing) :
16 | 		Shape(shape),
17 | 		Palette(palette),
18 | 		BaseNumberFrame(baseNumberFrame),
19 | 		BaseExtraFrame(baseExtraFrame),
20 | 		Spacing(spacing)
21 | 	{ }
22 | };
23 | 
24 | class ShapeTextPrinter
25 | {
26 | private:
27 | 
28 | 	static constexpr std::string_view SignSequence = "/%$,.!?|";
29 | 
30 | public:
31 | 
32 | 	static void PrintShape
33 | 	(
34 | 		const char* text,
35 | 		ShapeTextPrintData& data,
36 | 		Point2D position,
37 | 		RectangleStruct& bounds,
38 | 		DSurface* pSurface,
39 | 		Point2D offset = Point2D::Empty,
40 | 		BlitterFlags blitterFlags = BlitterFlags::None,
41 | 		int brightness = 1000,
42 | 		int tintColor = 0
43 | 	);
44 | };
45 | 


--------------------------------------------------------------------------------
/src/Utilities/Swizzle.h:
--------------------------------------------------------------------------------
 1 | #pragma once
 2 | 
 3 | // Ares has hooked the SwizzleManagerClass,
 4 | // so what we need to do is just call the original functions.
 5 | 
 6 | #include 
 7 | 
 8 | #include 
 9 | 
10 | class PhobosSwizzle
11 | {
12 | public:
13 | 	/**
14 | 	* pass in the *address* of the pointer you want to have changed
15 | 	* caution, after the call *p will be NULL
16 | 	*/
17 | 	inline static HRESULT RegisterForChange(void** p)
18 | 	{
19 | 		return SwizzleManagerClass::Instance.Swizzle(p);
20 | 	}
21 | 
22 | 	/**
23 | 	* the original game objects all save their `this` pointer to the save stream
24 | 	* that way they know what ptr they used and call this function with that old ptr and `this` as the new ptr
25 | 	*/
26 | 	inline static HRESULT RegisterChange(void* was, void* is)
27 | 	{
28 | 		return SwizzleManagerClass::Instance.Here_I_Am((long)was, is);
29 | 	}
30 | 
31 | 	template
32 | 	inline static void RegisterPointerForChange(T*& ptr)
33 | 	{
34 | 		auto pptr = const_cast**>(&ptr);
35 | 		RegisterForChange(reinterpret_cast(pptr));
36 | 	}
37 | };
38 | 
39 | struct Swizzle
40 | {
41 | 	template 
42 | 	Swizzle(T& object)
43 | 	{
44 | 		if constexpr (std::is_pointer_v)
45 | 			PhobosSwizzle::RegisterPointerForChange(object);
46 | 	}
47 | };
48 | 


--------------------------------------------------------------------------------
/src/version.rc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Phobos-developers/Phobos/72bbf8bbcff9a1ec88960ad2d2dbb0e5274e16bb/src/version.rc


--------------------------------------------------------------------------------